53 ExtendedData() : fObject(nullptr), fSmartClass(nullptr), fDispatchPtr(nullptr), fArraySize(0) {}
55 for (
auto& pc : fDatamemberCache)
56 Py_XDECREF(pc.second);
57 fDatamemberCache.clear();
68 CPyCppyy::CPPSmartClass* fSmartClass;
71 CPyCppyy::DispatchPtr* fDispatchPtr;
79#define EXT_OBJECT(pyobj) ((ExtendedData*)((pyobj)->fObject))->fObject
80#define DATA_CACHE(pyobj) ((ExtendedData*)((pyobj)->fObject))->fDatamemberCache
81#define SMART_CLS(pyobj) ((ExtendedData*)((pyobj)->fObject))->fSmartClass
82#define SMART_TYPE(pyobj) SMART_CLS(pyobj)->fCppType
83#define DISPATCHPTR(pyobj) ((ExtendedData*)((pyobj)->fObject))->fDispatchPtr
84#define ARRAY_SIZE(pyobj) ((ExtendedData*)((pyobj)->fObject))->fArraySize
90 fObject = (
void*)
new ExtendedData{};
111 if (!target) target =
Py_TYPE(self);
112 PyObject* newinst = target->tp_new(target,
nullptr,
nullptr);
119 PyObject* cpy = PyObject_GetAttrString(self, (
char*)
"__cpp_copy__");
120 if (cpy && PyCallable_Check(cpy)) {
123 PyTuple_SET_ITEM(args, 0, newinst);
124 PyObject* res = PyObject_CallObject(cpy, args);
143 bool bMergeOk = PyDict_Merge(newdct, selfdct, 1) == 0;
178 Py_INCREF(smart_type);
260 int result = PyObject_IsTrue(pylen);
281 PyObject *mname =
nullptr, *sigarg =
nullptr;
282 if (!PyArg_ParseTuple(args,
const_cast<char*
>(
"O!O!:__dispatch__"),
287 PyObject* pymeth = PyObject_GetAttr(self, mname);
292 PyObject* pydisp = PyObject_GetAttrString(pymeth,
const_cast<char*
>(
"__overload__"));
299 PyObject* oload = PyObject_CallFunctionObjArgs(pydisp, sigarg,
nullptr);
333 if (!PyTuple_Check(shape) || PyTuple_GET_SIZE(shape) != 1) {
334 PyErr_SetString(PyExc_TypeError,
"tuple object of size 1 expected");
338 long sz = PyLong_AsLong(PyTuple_GET_ITEM(shape, 0));
340 PyErr_SetString(PyExc_ValueError,
"array length must be positive");
357 PyErr_Format(PyExc_TypeError,
"%s object does not support indexing",
Py_TYPE(self)->tp_name);
364 PyErr_SetString(PyExc_IndexError,
"negative indices not supported for array of structs");
370 if (0 <= maxidx && maxidx <= idx) {
371 PyErr_SetString(PyExc_IndexError,
"index out of range");
376 unsigned flags = 0;
size_t sz =
sizeof(
void*);
384 void* indexed_obj = (
void*)(address+(uintptr_t)(idx*sz));
404 static PyCFunction reducer =
nullptr;
412 PyErr_SetString(PyExc_NotImplementedError,
"");
415 return reducer(self, args);
421 {(
char*)
"__destruct__", (PyCFunction)
op_destruct, METH_NOARGS,
422 (
char*)
"call the C++ destructor"},
423 {(
char*)
"__dispatch__", (PyCFunction)
op_dispatch, METH_VARARGS,
424 (
char*)
"dispatch to selected overload"},
426 (
char*)
"get associated smart pointer, if any"},
427 {(
char*)
"__reduce__", (PyCFunction)
op_reduce, METH_NOARGS,
428 (
char*)
"reduce method for serialization"},
429 {(
char*)
"__reshape__", (PyCFunction)
op_reshape, METH_O,
430 (
char*)
"cast pointer to 1D array type"},
431 {(
char*)
nullptr,
nullptr, 0,
nullptr}
450 PyObject_GC_UnTrack((
PyObject*)pyobj);
473 void* rawcpp = ((
CPPInstance*)self)->GetObjectRaw();
492 const char* cppop = op == Py_EQ ?
"==" :
"!=";
493 PyCallable* pyfunc = FindBinaryOperator(self, obj, cppop);
504 if (binop == Py_None) {
506 if (binop && binop != Py_None) flipit =
true;
509 if (!binop || binop == Py_None)
return nullptr;
512 Py_INCREF(obj); PyTuple_SET_ITEM(args, 0, obj);
525 if (!flipit)
return result;
527 int istrue = PyObject_IsTrue(result);
542 if (clActual && clActual != klass) {
544 clActual, klass, address, -1 ,
true );
545 if (offset != -1) address = (
void*)((intptr_t)address + offset);
552#define CPYCPPYY_ORDERED_OPERATOR_STUB(op, ometh, label) \
554 PyCallable* pyfunc = Utility::FindBinaryOperator((PyObject*)self, other, #op);\
556 ometh = (PyObject*)CPPOverload_New(#label, pyfunc); \
573 if (op == Py_EQ || op == Py_NE) {
577 "\nComparison of C++ nullptr objects with `None` is no longer supported."
578 "\n\nPreviously, `None` was treated as equivalent to a null C++ pointer, "
579 "but this led to confusing behavior where `x == None` could be True even though `x is None` was False."
580 "\n\nTo test whether a C++ object is null or not, check its truth value instead:"
582 "\nor use `x is None` to explicitly check for Python None."
585 PyErr_SetString(PyExc_TypeError, msg);
593 if (result)
return result;
600 self->GetObject() == ((
CPPInstance*)other)->GetObject())) {
607 bIsEq = addr1 && addr2 && (addr1 == addr2);
610 if ((op == Py_EQ && bIsEq) || (op == Py_NE && !bIsEq))
617 else if (op == Py_LT || op == Py_LE || op == Py_GT || op == Py_GE) {
638 PyErr_SetString(PyExc_NotImplementedError,
"");
642 return PyObject_CallFunctionObjArgs(meth, (
PyObject*)self, other,
nullptr);
645 Py_INCREF(Py_NotImplemented);
646 return Py_NotImplemented;
656 return PyBaseObject_Type.tp_repr((
PyObject*)self);
670 const_cast<char*
>(
"<%s.%s object at %p held by %s at %p>"),
687 if (
sizeof(
unsigned long) >=
sizeof(
size_t))
688 return (
Py_hash_t)PyLong_AsUnsignedLong(obj);
689 return (
Py_hash_t)PyLong_AsUnsignedLongLong(obj);
710 bool isValid = PyMapping_HasKeyString(dct, (
char*)
"__call__");
713 PyObject* hashobj = PyObject_CallObject(hashcls,
nullptr);
719 PyObject* hashval = PyObject_CallFunctionObjArgs(hashobj, (
PyObject*)self,
nullptr);
730 ((PyTypeObject*)
Py_TYPE(self))->tp_hash = PyBaseObject_Type.tp_hash;
731 return PyBaseObject_Type.tp_hash((
PyObject*)self);
738 std::ostringstream s;
741#if PY_VERSION_HEX >= 0x03000000
749 if (isBound) res = PyObject_CallFunctionObjArgs(lshift, pys, NULL);
750 else res = PyObject_CallFunctionObjArgs(lshift, pys, pyobj, NULL);
753#if PY_VERSION_HEX >= 0x03000000
794 else if (pyname == (
PyObject*)0x01) {
807 }
else if (pyname == (
PyObject*)0x02) {
816 PyObject* lshift = PyObject_GetAttr(
835 static PyObject* printValue =
nullptr;
837 PyObject* gbl = PyDict_GetItemString(PySys_GetObject((
char*)
"modules"),
"cppyy.gbl");
838 PyObject* cl = PyObject_GetAttrString(gbl, (
char*)
"cling");
839 printValue = PyObject_GetAttrString(cl, (
char*)
"printValue");
843 Py_DECREF(printValue);
844 if (!PyCallable_Check(printValue))
845 printValue =
nullptr;
865 PyObject* OL = PyObject_GetItem(printValue, clName);
868 PyObject* pretty = OL ? PyObject_CallFunctionObjArgs(OL, byref,
nullptr) :
nullptr;
874 const std::string& pv = *(std::string*)((
CPPInstance*)pretty)->GetObject();
875 if (!pv.empty() && pv.find(
"@0x") == std::string::npos)
878 if (result)
return result;
902 long shouldown = PyLong_AsLong(value);
903 if (shouldown == -1 && PyErr_Occurred()) {
904 PyErr_SetString(PyExc_ValueError,
"__python_owns__ should be either True or False");
917 (
char*)
"If true, python manages the life time of this object",
nullptr},
918 {(
char*)
nullptr,
nullptr,
nullptr,
nullptr,
nullptr}
923#define CPYCPPYY_STUB_BODY(name, op) \
924 bool previously_resolved_overload = (bool)meth; \
927 PyCallable* pyfunc = Utility::FindBinaryOperator(left, right, #op); \
928 if (pyfunc) meth = (PyObject*)CPPOverload_New(#name, pyfunc); \
930 PyErr_SetString(PyExc_NotImplementedError, ""); \
934 PyObject* res = PyObject_CallFunctionObjArgs(meth, cppobj, other, nullptr);\
935 if (!res && previously_resolved_overload) { \
938 PyCallable* pyfunc = Utility::FindBinaryOperator(left, right, #op); \
939 if (pyfunc) ((CPPOverload*&)meth)->AdoptMethod(pyfunc); \
941 PyErr_SetString(PyExc_NotImplementedError, ""); \
945 res = PyObject_CallFunctionObjArgs(meth, cppobj, other, nullptr); \
950#define CPYCPPYY_OPERATOR_STUB(name, op, ometh) \
951static PyObject* op_##name##_stub(PyObject* left, PyObject* right) \
954 CPPClass* klass = (CPPClass*)Py_TYPE(left); \
955 if (!klass->fOperators) klass->fOperators = new Utility::PyOperators{}; \
956 PyObject*& meth = ometh; \
957 PyObject *cppobj = left, *other = right; \
958 CPYCPPYY_STUB_BODY(name, op) \
961#define CPYCPPYY_ASSOCIATIVE_OPERATOR_STUB(name, op, lmeth, rmeth) \
962static PyObject* op_##name##_stub(PyObject* left, PyObject* right) \
965 CPPClass* klass; PyObject** pmeth; \
966 PyObject *cppobj, *other; \
967 if (CPPInstance_Check(left)) { \
968 klass = (CPPClass*)Py_TYPE(left); \
969 if (!klass->fOperators) klass->fOperators = new Utility::PyOperators{};\
970 pmeth = &lmeth; cppobj = left; other = right; \
971 } else if (CPPInstance_Check(right)) { \
972 klass = (CPPClass*)Py_TYPE(right); \
973 if (!klass->fOperators) klass->fOperators = new Utility::PyOperators{};\
974 pmeth = &rmeth; cppobj = right; other = left; \
976 PyErr_SetString(PyExc_NotImplementedError, ""); \
979 PyObject*& meth = *pmeth; \
980 CPYCPPYY_STUB_BODY(name, op) \
983#define CPYCPPYY_UNARY_OPERATOR(name, op, label) \
984static PyObject* op_##name##_stub(PyObject* pyobj) \
987 PyCallable* pyfunc = Utility::FindUnaryOperator((PyObject*)Py_TYPE(pyobj), #op);\
988 if (pyfunc && Utility::AddToClass((PyObject*)Py_TYPE(pyobj), #label, pyfunc))\
989 return PyObject_CallMethod(pyobj, (char*)#label, nullptr); \
990 PyErr_SetString(PyExc_NotImplementedError, ""); \
1007#if PY_VERSION_HEX < 0x03000000
1023#if PY_VERSION_HEX < 0x03000000
1029#if PY_VERSION_HEX < 0x03000000
1036#if PY_VERSION_HEX < 0x03000000
1046#if PY_VERSION_HEX >= 0x02020000
1048#if PY_VERSION_HEX < 0x03000000
1056#if PY_VERSION_HEX >= 0x02050000
1059#if PY_VERSION_HEX >= 0x03050000
1069 (
char*)
"cppyy.CPPInstance",
1087 Py_TPFLAGS_DEFAULT |
1088 Py_TPFLAGS_BASETYPE |
1089 Py_TPFLAGS_CHECKTYPES |
1091 (
char*)
"cppyy object proxy (internal)",
1116#
if PY_VERSION_HEX >= 0x02030000
1119#
if PY_VERSION_HEX >= 0x02060000
1122#
if PY_VERSION_HEX >= 0x03040000
1125#
if PY_VERSION_HEX >= 0x03080000
1128#
if PY_VERSION_HEX >= 0x030c0000
1131#
if PY_VERSION_HEX >= 0x030d0000
#define CPYCPPYY_UNARY_OPERATOR(name, op, label)
#define EXT_OBJECT(pyobj)
#define SMART_TYPE(pyobj)
#define CPYCPPYY_OPERATOR_STUB(name, op, ometh)
#define DATA_CACHE(pyobj)
#define DISPATCHPTR(pyobj)
#define CPYCPPYY_ORDERED_OPERATOR_STUB(op, ometh, label)
#define CPYCPPYY_ASSOCIATIVE_OPERATOR_STUB(name, op, lmeth, rmeth)
#define CPyCppyy_PyText_AsString
#define CPyCppyy_PyText_FromFormat
#define CPyCppyy_PyText_Type
#define CPyCppyy_PyText_FromString
#define PyVarObject_HEAD_INIT(type, size)
#define ARRAY_SIZE(array)
Cppyy::TCppType_t GetSmartIsA() const
void CastToArray(Py_ssize_t sz)
CPPInstance * Copy(void *cppinst, PyTypeObject *target=nullptr)
CI_DatamemberCache_t & GetDatamemberCache()
void SetSmart(PyObject *smart_type)
PyObject_HEAD void * fObject
void * GetExtendedObject()
static PyCFunction & ReduceMethod()
Cppyy::TCppType_t ObjectIsA(bool check_smart=true) const
void SetDispatchPtr(void *)
Utility::PyOperators * fOperators
static bool RegisterPyObject(CPPInstance *pyobj, void *cppobj)
static bool UnregisterPyObject(CPPInstance *pyobj, PyObject *pyclass)
std::string extract_namespace(const std::string &name)
PyCallable * FindBinaryOperator(PyObject *left, PyObject *right, const char *op, Cppyy::TCppScope_t scope=0)
bool AddToClass(PyObject *pyclass, const char *label, PyCFunction cfunc, int flags=METH_VARARGS)
std::string ClassName(PyObject *pyobj)
CPPOverload * CPPOverload_New(const std::string &name, std::vector< PyCallable * > &methods)
PyTypeObject CPPInstance_Type
static PyObject * op_str_internal(PyObject *pyobj, PyObject *lshift, bool isBound)
PyObject * op_reduce(PyObject *self, PyObject *args)
static PyObject * op_div_stub(PyObject *left, PyObject *right)
static void ScopeFlagSet(CPPInstance *self, CPPScope::EFlags flag)
static Py_hash_t CPyCppyy_PyLong_AsHash_t(PyObject *obj)
PyObject * CreateScopeProxy(Cppyy::TCppScope_t, const unsigned flags=0)
static int op_nonzero(CPPInstance *self)
static PyObject * op_mul_stub(PyObject *left, PyObject *right)
static PySequenceMethods op_as_sequence
static PyMethodDef op_methods[]
static PyObject * op_repr(CPPInstance *self)
static PyObject * op_item(CPPInstance *self, Py_ssize_t idx)
PyObject * BindCppObjectNoCast(Cppyy::TCppObject_t object, Cppyy::TCppType_t klass, const unsigned flags=0)
static PyObject * op_richcompare(CPPInstance *self, PyObject *other, int op)
std::vector< std::pair< ptrdiff_t, PyObject * > > CI_DatamemberCache_t
static int op_setownership(CPPInstance *pyobj, PyObject *value, void *)
bool CPPScope_Check(T *object)
static PyObject * eqneq_binop(CPPClass *klass, PyObject *self, PyObject *obj, int op)
static PyObject * op_getownership(CPPInstance *pyobj, void *)
static PyObject * op_neg_stub(PyObject *pyobj)
static int op_clear(CPPInstance *pyobj)
static PyObject * op_sub_stub(PyObject *left, PyObject *right)
void op_dealloc_nofree(CPPInstance *)
bool CPPInstance_Check(T *object)
static PyObject * op_reshape(CPPInstance *self, PyObject *shape)
static PyGetSetDef op_getset[]
PyObject * gNullPtrObject
PyTypeObject CPPOverload_Type
static PyNumberMethods op_as_number
static void * cast_actual(void *obj)
static PyObject * op_str(CPPInstance *self)
static void op_dealloc(CPPInstance *pyobj)
static PyObject * op_pos_stub(PyObject *pyobj)
static PyObject * op_add_stub(PyObject *left, PyObject *right)
static Py_hash_t op_hash(CPPInstance *self)
static PyObject * op_dispatch(PyObject *self, PyObject *args, PyObject *)
static PyObject * op_invert_stub(PyObject *pyobj)
PyTypeObject CPPScope_Type
static bool ScopeFlagCheck(CPPInstance *self, CPPScope::EFlags flag)
static PyObject * op_get_smartptr(CPPInstance *self)
static CPPInstance * op_new(PyTypeObject *subtype, PyObject *, PyObject *)
static int op_traverse(CPPInstance *, visitproc, void *)
static PyObject * op_destruct(CPPInstance *self)
RPY_EXPORTED ptrdiff_t GetBaseOffset(TCppType_t derived, TCppType_t base, TCppObject_t address, int direction, bool rerror=false)
RPY_EXPORTED size_t SizeOf(TCppType_t klass)
RPY_EXPORTED std::string ToString(TCppType_t klass, TCppObject_t obj)
RPY_EXPORTED void CallDestructor(TCppType_t type, TCppObject_t self)
RPY_EXPORTED void Destruct(TCppType_t type, TCppObject_t instance)
RPY_EXPORTED TCppType_t GetActualClass(TCppType_t klass, TCppObject_t obj)
RPY_EXPORTED std::string GetScopedFinalName(TCppType_t type)
RPY_EXPORTED void Deallocate(TCppType_t type, TCppObject_t instance)
RPY_EXPORTED void * CallR(TCppMethod_t method, TCppObject_t self, size_t nargs, void *args)
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
RPY_EXPORTED std::string GetFinalName(TCppType_t type)