26#if PY_VERSION_HEX < 0x030b0000
46 struct InitOperatorMapping_t {
48 InitOperatorMapping_t() {
117#if PY_VERSION_HEX < 0x03000000
123 } initOperatorMapping_;
132 if (PyFloat_Check(pyobject)) {
133 PyErr_SetString(PyExc_TypeError,
"can\'t convert float to unsigned long");
134 return (
unsigned long)-1;
136 return (
unsigned long)0;
139 unsigned long ul = PyLong_AsUnsignedLong(pyobject);
140 if (PyErr_Occurred() && PyInt_Check(pyobject)) {
142 long i = PyInt_AS_LONG(pyobject);
144 ul = (
unsigned long)i;
146 PyErr_SetString(PyExc_ValueError,
147 "can\'t convert negative value to unsigned long");
148 return (
unsigned long)-1;
159 if (PyFloat_Check(pyobject)) {
160 PyErr_SetString(PyExc_TypeError,
"can\'t convert float to unsigned long long");
163 return (
unsigned long)0;
167 if (PyErr_Occurred() && PyInt_Check(pyobject)) {
169 long i = PyInt_AS_LONG(pyobject);
173 PyErr_SetString(PyExc_ValueError,
174 "can\'t convert negative value to unsigned long long");
183 PyObject* pyclass,
const char* label, PyCFunction cfunc,
int flags)
188 static std::list<PyMethodDef> s_pymeths;
190 s_pymeths.push_back(PyMethodDef());
191 PyMethodDef* pdef = &s_pymeths.back();
192 pdef->ml_name =
const_cast<char*
>(label);
193 pdef->ml_meth = cfunc;
194 pdef->ml_flags = flags;
195 pdef->ml_doc =
nullptr;
197 PyObject* func = PyCFunction_New(pdef,
nullptr);
200 bool isOk = PyType_Type.tp_setattro(pyclass,
name, method) == 0;
205 if (PyErr_Occurred())
209 PyErr_Format(PyExc_TypeError,
"could not add method %s", label);
220 PyObject* pyfunc = PyObject_GetAttrString(pyclass,
const_cast<char*
>(func));
225 bool isOk = PyType_Type.tp_setattro(pyclass, pylabel, pyfunc) == 0;
237 (
CPPOverload*)PyObject_GetAttrString(pyclass,
const_cast<char*
>(label));
241 if (PyErr_Occurred())
246 bool isOk = PyType_Type.tp_setattro(pyclass, pylabel, (
PyObject*)method) == 0;
265 std::string opname =
"operator";
300 bool reverse =
false;
309 const std::string& lcname =
ClassName(left);
310 const std::string& rcname =
ClassName(right);
316 const std::string& lcname,
const std::string& rcname,
323 if (rcname ==
"<unknown>" || lcname ==
"<unknown>")
331 if (lcname ==
"str" || lcname ==
"unicode" || lcname ==
"complex")
358 && lcname.find(
"__wrap_iter") == std::string::npos
371 std::stringstream fname,
proto;
372 if (strncmp(op,
"==", 2) == 0) { fname <<
"is_equal<"; }
373 else if (strncmp(op,
"!=", 2) == 0) { fname <<
"is_not_equal<"; }
374 else { fname <<
"not_implemented<"; }
375 fname << lcname <<
", " << rcname <<
">";
376 proto <<
"const " << lcname <<
"&, const " << rcname;
378 if (method) pyfunc =
new CPPFunction(s_intern, method);
392 pystr = PyObject_Str(pyobj);
412#if PY_VERSION_HEX < 0x03000000
413 long l = PyInt_AS_LONG(arg);
414 tmpl_name.append((
l < INT_MIN || INT_MAX <
l) ?
"long" :
"int");
422 tmpl_name.append(
"int");
424 tmpl_name.append(
"unsigned long long");
426 tmpl_name.append((ll < INT_MIN || INT_MAX < ll) ? \
427 ((ll < LONG_MIN || LONG_MAX < ll) ?
"long long" :
"long") :
"int");
430 tmpl_name.append(
"int");
435#if PY_VERSION_HEX < 0x03000000
436 if (tn == (
PyObject*)&PyLong_Type) {
444 tmpl_name.append(
"long");
446 tmpl_name.append(
"unsigned long long");
448 tmpl_name.append((ll < LONG_MIN || LONG_MAX < ll) ?
"long long" :
"long");
450 tmpl_name.append(
"long");
456 if (tn == (
PyObject*)&PyFloat_Type) {
458 tmpl_name.append(arg ?
"double" :
"float");
462#if PY_VERSION_HEX < 0x03000000
463 if (tn == (
PyObject*)&PyString_Type) {
465 if (tn == (
PyObject*)&PyUnicode_Type) {
467 tmpl_name.append(
"std::string");
472 if (arg && PySequence_Size(arg)) {
473 std::string subtype{
"std::initializer_list<"};
474 PyObject* item = PySequence_GetItem(arg, 0);
477 tmpl_name.append(subtype);
478 tmpl_name.append(
">");
486 if (CPPScope_Check(tn)) {
491 if (CPPInstance_Check(pyobj)) {
492 if (pyobj->
fFlags & CPPInstance::kIsRValue)
493 tmpl_name.append(
"&&");
495 if (pcnt) *pcnt += 1;
496 if ((pyobj->
fFlags & CPPInstance::kIsReference) || pref ==
kPointer)
497 tmpl_name.push_back(
'*');
499 tmpl_name.push_back(
'&');
507 if (tn == (
PyObject*)&CPPOverload_Type) {
509 PyObject_GetAttr(arg, PyStrings::gCppName) : \
510 CPyCppyy_PyText_FromString(
"void* (*)(...)");
517 if (arg && PyCallable_Check(arg)) {
518 PyObject* annot = PyObject_GetAttr(arg, PyStrings::gAnnotations);
520 if (PyDict_Check(annot) && 1 < PyDict_Size(annot)) {
521 PyObject* ret = PyDict_GetItemString(annot,
"return");
524 std::ostringstream tpn;
528 PyObject* values = PyDict_Values(annot);
529 for (
Py_ssize_t i = 0; i < (PyList_GET_SIZE(values)-1); ++i) {
531 PyObject* item = PyList_GET_ITEM(values, i);
537 tmpl_name.append(tpn.str());
548 PyObject* tpName = PyObject_GetAttr(arg, PyStrings::gCppName);
557 for (
auto nn : {PyStrings::gCppName, PyStrings::gName}) {
558 PyObject* tpName = PyObject_GetAttr(tn, nn);
567 if (PyInt_Check(tn) || PyLong_Check(tn) || PyFloat_Check(tn)) {
585 bool justOne = !PyTuple_CheckExact(tpArgs);
588 std::string tmpl_name;
589 tmpl_name.reserve(128);
592 tmpl_name.push_back(
'<');
596 Py_ssize_t nArgs = justOne ? 1 : PyTuple_GET_SIZE(tpArgs);
597 for (
int i = argoff; i < nArgs; ++i) {
599 PyObject* tn = justOne ? tpArgs : PyTuple_GET_ITEM(tpArgs, i);
605 if (!
AddTypeName(tmpl_name, tn, (args ? PyTuple_GET_ITEM(args, i) :
nullptr), pref, pcnt)) {
606 PyErr_SetString(PyExc_SyntaxError,
607 "could not construct C++ name from provided template argument.");
614 tmpl_name.push_back(
',');
618 tmpl_name.push_back(
'>');
630 const std::vector<std::string>& argtypes, std::ostringstream& code)
633 int nArgs = (
int)argtypes.size();
636 bool isVoid = retType ==
"void";
638 code <<
" CPYCPPYY_STATIC std::unique_ptr<CPyCppyy::Converter, std::function<void(CPyCppyy::Converter*)>> "
639 "retconv{CPyCppyy::CreateConverter(\""
640 << retType <<
"\"), CPyCppyy::DestroyConverter};\n";
641 std::vector<bool> arg_is_ptr;
643 arg_is_ptr.reserve(nArgs);
644 code <<
" CPYCPPYY_STATIC std::vector<std::unique_ptr<CPyCppyy::Converter, std::function<void(CPyCppyy::Converter*)>>> argcvs;\n"
645 <<
" if (argcvs.empty()) {\n"
646 <<
" argcvs.reserve(" << nArgs <<
");\n";
647 for (
int i = 0; i < nArgs; ++i) {
648 arg_is_ptr[i] =
false;
649 code <<
" argcvs.emplace_back(CPyCppyy::CreateConverter(\"";
650 const std::string& at = argtypes[i];
652 const std::string& cpd = TypeManip::compound(res_at);
659 arg_is_ptr[i] = cpd.back() ==
'*';
660 if (arg_is_ptr[i] || cpd.back() ==
'&') {
661 code << res_at.substr(0, res_at.size()-1);
665 code <<
"\"), CPyCppyy::DestroyConverter);\n";
672 code <<
" " << retType <<
" ret{};\n";
675 code <<
" PyGILState_STATE state = PyGILState_Ensure();\n";
679 code <<
" std::vector<PyObject*> pyargs;\n";
680 code <<
" pyargs.reserve(" << nArgs <<
");\n"
682 for (
int i = 0; i < nArgs; ++i) {
683 code <<
" pyargs.emplace_back(argcvs[" << i <<
"]->FromMemory((void*)";
684 if (!arg_is_ptr[i]) code <<
'&';
685 code <<
"arg" << i <<
"));\n"
686 <<
" if (!pyargs.back()) throw " << i <<
";\n";
688 code <<
" } catch(int) {\n"
689 <<
" for (auto pyarg : pyargs) Py_XDECREF(pyarg);\n"
690 <<
" CPyCppyy::PyException pyexc; PyGILState_Release(state); throw pyexc;\n"
698 bool isVoid = retType ==
"void";
702 code <<
" for (auto pyarg : pyargs) Py_DECREF(pyarg);\n";
703 code <<
" bool cOk = (bool)pyresult;\n"
704 " if (pyresult) {\n";
708 code <<
" if (!CPyCppyy::Instance_IsLively(pyresult))\n"
712 code << (isVoid ?
"" :
" cOk = retconv->ToMemory(pyresult, (void*)&ret);\n")
713 <<
" Py_DECREF(pyresult);\n }\n";
714 if (isPtr) code <<
" }\n";
715 code <<
" if (!cOk) {"
719 " /* do nothing */ }\n"
721 " CPyCppyy::PyException pyexc; PyGILState_Release(state); throw pyexc; }\n"
723 " PyGILState_Release(state);\n"
725 code << (isVoid ?
";\n }\n" :
" ret;\n }\n");
733 const std::string& retType,
const std::string& signature,
void* address)
736 static int maker_count = 0;
740 Py_INCREF(pf->second);
748 std::ostringstream fname;
749 fname <<
"ptr2func" << ++maker_count;
751 std::ostringstream code;
752 code <<
"namespace __cppyy_internal { std::function<"
753 << retType << signature <<
"> " << fname.str()
754 <<
"(intptr_t faddr) { return (" << retType <<
"(*)" << signature <<
")faddr;} }";
757 PyErr_SetString(PyExc_TypeError,
"conversion to std::function failed");
762 maker = PyObject_GetAttrString(pyscope, fname.str().c_str());
773 PyTuple_SET_ITEM(args, 0, PyLong_FromLongLong((intptr_t)address));
774 PyObject* func = PyObject_Call(maker, args, NULL);
778 ((
CPPInstance*)func)->fFlags |= CPPInstance::kIsLValue;
793 if (PyType_Ready(pytype) < 0)
798 if (PyModule_AddObject(module, (
char*)
name, (
PyObject*)pytype) < 0) {
817 if ((!check || tc ==
'*' || tc ==
'B') && PyByteArray_CheckExact(pyobject)) {
818 buf = PyByteArray_AS_STRING(pyobject);
819 return PyByteArray_GET_SIZE(pyobject);
823 if (PyObject_CheckBuffer(pyobject)) {
824 if (PySequence_Check(pyobject) && !PySequence_Size(pyobject))
828 memset(&bufinfo, 0,
sizeof(Py_buffer));
829 if (PyObject_GetBuffer(pyobject, &bufinfo, PyBUF_FORMAT) == 0) {
830 if (tc ==
'*' || strchr(bufinfo.format, tc)
834 || (
sizeof(
long int) ==
sizeof(
int) && ((tc ==
'I' && strchr(bufinfo.format,
'L')) ||
835 (tc ==
'i' && strchr(bufinfo.format,
'l'))))
837 || (tc ==
'z' && strstr(bufinfo.format,
"Zf"))
839 || (tc ==
'?' && strchr(bufinfo.format,
'b'))
843 if (check && bufinfo.itemsize !=
size) {
844 PyErr_Format(PyExc_TypeError,
845 "buffer itemsize (%ld) does not match expected size (%d)", bufinfo.itemsize,
size);
851 if (buf && bufinfo.ndim == 0)
852 buflen = bufinfo.len/bufinfo.itemsize;
853 else if (buf && bufinfo.ndim == 1)
854 buflen = bufinfo.shape ? bufinfo.shape[0] : bufinfo.len/bufinfo.itemsize;
864 }
else if (bufinfo.obj)
870 PyBufferProcs* bufprocs =
Py_TYPE(pyobject)->tp_as_buffer;
872 PySequenceMethods* seqmeths =
Py_TYPE(pyobject)->tp_as_sequence;
873 if (seqmeths != 0 && bufprocs != 0
874#
if PY_VERSION_HEX < 0x03000000
875 && bufprocs->bf_getwritebuffer != 0
876 && (*(bufprocs->bf_getsegcount))(pyobject, 0) == 1
878 && bufprocs->bf_getbuffer != 0
883#if PY_VERSION_HEX < 0x03000000
884 Py_ssize_t buflen = (*(bufprocs->bf_getwritebuffer))(pyobject, 0, &buf);
887 (*(bufprocs->bf_getbuffer))(pyobject, &bufinfo, PyBUF_WRITABLE);
888 buf = (
char*)bufinfo.buf;
893 if (buf && check ==
true) {
895 PyObject* pytc = tc !=
'*' ? PyObject_GetAttr(pyobject, PyStrings::gTypeCode) :
nullptr;
898 if (!(cpytc == tc || (tc ==
'?' && cpytc ==
'b')))
901 }
else if (seqmeths->sq_length &&
902 (
int)(buflen/(*(seqmeths->sq_length))(pyobject)) ==
size) {
905 }
else if (buflen ==
size) {
912 PyObject* pytype = 0, *pyvalue = 0, *pytrace = 0;
913 PyErr_Fetch(&pytype, &pyvalue, &pytrace);
915 (
char*)
"%s and given element size (%ld) do not match needed (%d)",
917 seqmeths->sq_length ? (
long)(buflen/(*(seqmeths->sq_length))(pyobject)) : (long)buflen,
920 PyErr_Restore(pytype, pyvalue2, pytrace);
935 if (8 <
name.size() &&
name.substr(0, 8) ==
"operator") {
936 std::string op =
name.substr(8, std::string::npos);
939 std::string::size_type start = 0, end = op.size();
940 while (start < end && isspace(op[start])) ++start;
941 while (start < end && isspace(op[end-1])) --end;
942 op = op.substr(start, end - start);
959 }
else if (op ==
"*") {
961 if (!bTakesParams)
return "__deref__";
962 if (stubbed) *stubbed =
true;
965 }
else if (op ==
"/") {
969 }
else if (op ==
"+") {
971 if (!bTakesParams)
return "__pos__";
972 if (stubbed) *stubbed =
true;
975 }
else if (op ==
"-") {
977 if (!bTakesParams)
return "__neg__";
978 if (stubbed) *stubbed =
true;
981 }
else if (op ==
"++") {
983 return bTakesParams ?
"__postinc__" :
"__preinc__";
985 }
else if (op ==
"--") {
987 return bTakesParams ?
"__postdec__" :
"__predec__";
1000 std::string clname =
"<unknown>";
1002 PyObject* pyname = PyObject_GetAttr(pyclass, PyStrings::gCppName);
1005 pyname = PyObject_GetAttr(pyclass, PyStrings::gName);
1022 std::string
tt =
"<int>::";
1023 for (
auto c : {
"std::vector",
"std::list",
"std::deque"}) {
1024 for (
auto i : {
"iterator",
"const_iterator"}) {
1026 auto pos = itname.find(
'<');
1027 if (pos != std::string::npos)
1033 auto pos = classname.find(
'<');
1034 if (pos != std::string::npos)
1059#if PY_VERSION_HEX >= 0x02030000
1060 PyGILState_STATE gstate = PyGILState_Ensure();
1062 PyGILState_Release(gstate);
1064 if (PyThreadState_GET())
1065 return PyErr_Occurred();
1077 if (PyErr_Occurred()) {
1079 PyErr_Fetch(&
e.fType, &
e.fValue, &
e.fTrace);
1080 errors.push_back(
e);
1082 return errors.size();
1089 if (errors.empty()) {
1098 for (
auto&
e : errors) {
1100 if (!unique_from_cpp)
1101 unique_from_cpp = &
e;
1104 unique_from_cpp =
nullptr;
1110 if (unique_from_cpp) {
1117 Py_INCREF(unique_from_cpp->
fType); Py_INCREF(unique_from_cpp->
fValue); Py_XINCREF(unique_from_cpp->
fTrace);
1118 PyErr_Restore(unique_from_cpp->
fType, unique_from_cpp->
fValue, unique_from_cpp->
fTrace);
1122 for (
auto&
e : errors) {
1123 if (!exc_type) exc_type =
e.fType;
1124 else if (exc_type !=
e.fType) {
1132 for (
auto&
e : errors) {
1136 }
else if (
e.fValue) {
1137 PyObject* excstr = PyObject_Str(
e.fValue);
1149 Py_DECREF(separator);
1169 "#include \"CPyCppyy/API.h\"\n"
1172 "#include \"CPyCppyy/DispatchPtr.h\"\n"
1173 "#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
void CPyCppyy_PyBuffer_Release(PyObject *, Py_buffer *view)
#define CPyCppyy_PyText_FromFormat
#define CPyCppyy_PyText_FromString
#define CPyCppyy_PyText_Check
unsigned long long PY_ULONG_LONG
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
static std::set< std::string > sIteratorTypes
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)
static bool check_scope(const std::string &name)
std::map< std::string, std::string > TC2POperatorMapping_t
static std::string AnnotationAsText(PyObject *pyobj)
void AdoptMethod(PyCallable *pc)
Cppyy::TCppType_t fCppType
std::string clean_type(const std::string &cppname, bool template_strip=true, bool const_strip=true)
PyCallable * FindBinaryOperator(PyObject *left, PyObject *right, const char *op, Cppyy::TCppScope_t scope=0)
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)
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)
size_t FetchError(std::vector< PyError_t > &, bool is_cpp=false)
std::string MapOperatorName(const std::string &name, bool bTakesParames, bool *stubbed=nullptr)
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)
bool IsSTLIterator(const std::string &classname)
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 * gDefaultObject
PyObject * CustomInstanceMethod_New(PyObject *func, PyObject *self, PyObject *pyclass)
dict_lookup_func gDictLookupOrg
PyObject * CreateScopeProxy(Cppyy::TCppScope_t, const unsigned flags=0)
bool CPPOverload_Check(T *object)
bool CPPScope_Check(T *object)
PY_ULONG_LONG PyLongOrInt_AsULong64(PyObject *pyobject)
bool CPPInstance_Check(T *object)
PyObject * gNullPtrObject
RPY_EXPORTED bool Compile(const std::string &code, bool silent=false)
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)
static void Clear(PyError_t &e)