56 : fObject(nullptr), fSmartClass(nullptr), fDispatchPtr(nullptr),
59 for (
auto& pc : fDatamemberCache)
60 Py_XDECREF(pc.second);
61 fDatamemberCache.clear();
78 Py_ssize_t fArraySize;
83#define EXT_OBJECT(pyobj) ((ExtendedData*)((pyobj)->fObject))->fObject
84#define DATA_CACHE(pyobj) ((ExtendedData*)((pyobj)->fObject))->fDatamemberCache
85#define SMART_CLS(pyobj) ((ExtendedData*)((pyobj)->fObject))->fSmartClass
86#define SMART_TYPE(pyobj) SMART_CLS(pyobj)->fCppType
87#define DISPATCHPTR(pyobj) ((ExtendedData*)((pyobj)->fObject))->fDispatchPtr
88#define ARRAY_SIZE(pyobj) ((ExtendedData*)((pyobj)->fObject))->fArraySize
94 fObject = (
void*)
new ExtendedData{};
123 PyObject* cpy = PyObject_GetAttrString(self, (
char*)
"__cpp_copy__");
124 if (cpy && PyCallable_Check(cpy)) {
127 PyTuple_SET_ITEM(args, 0, newinst);
128 PyObject* res = PyObject_CallObject(cpy, args);
147 bool bMergeOk = PyDict_Merge(newdct, selfdct, 1) == 0;
178 Py_INCREF(smart_type);
236 delete (ExtendedData*)pyobj->
fObject;
268 int result = PyObject_IsTrue(pylen);
289 PyObject *mname =
nullptr, *sigarg =
nullptr;
290 if (!PyArg_ParseTuple(args,
const_cast<char*
>(
"O!O!:__dispatch__"),
291 &PyUnicode_Type, &mname, &PyUnicode_Type, &sigarg))
295 PyObject* pymeth = PyObject_GetAttr(self, mname);
301 PyObject_GetAttrString(pymeth,
const_cast<char*
>(
"__overload__"));
308 PyObject* oload = PyObject_CallFunctionObjArgs(pydisp, sigarg,
nullptr);
340 if (!PyTuple_Check(shape) || PyTuple_GET_SIZE(shape) != 1) {
341 PyErr_SetString(PyExc_TypeError,
"tuple object of size 1 expected");
345 long sz = PyLong_AsLong(PyTuple_GET_ITEM(shape, 0));
347 PyErr_SetString(PyExc_ValueError,
"array length must be positive");
363 PyErr_Format(PyExc_TypeError,
"%s object does not support indexing",
364 Py_TYPE(self)->tp_name);
372 PyErr_SetString(PyExc_IndexError,
373 "negative indices not supported for array of structs");
379 if (0 <= maxidx && maxidx <= idx) {
380 PyErr_SetString(PyExc_IndexError,
"index out of range");
386 size_t sz =
sizeof(
void*);
395 void* indexed_obj = (
void*)(address + (uintptr_t)(idx * sz));
416 static PyCFunction reducer =
nullptr;
423 PyErr_SetString(PyExc_NotImplementedError,
"");
426 return reducer(self, args);
431 {(
char*)
"__destruct__", (PyCFunction)
op_destruct, METH_NOARGS,
432 (
char*)
"call the C++ destructor"},
433 {(
char*)
"__dispatch__", (PyCFunction)
op_dispatch, METH_VARARGS,
434 (
char*)
"dispatch to selected overload"},
436 (
char*)
"get associated smart pointer, if any"},
437 {(
char*)
"__reduce__", (PyCFunction)
op_reduce, METH_NOARGS,
438 (
char*)
"reduce method for serialization"},
439 {(
char*)
"__reshape__", (PyCFunction)
op_reshape, METH_O,
440 (
char*)
"cast pointer to 1D array type"},
441 {(
char*)
nullptr,
nullptr, 0,
nullptr}};
456 PyObject_GC_UnTrack((
PyObject*)pyobj);
475 using namespace Utility;
479 void* rawcpp = ((
CPPInstance*)self)->GetObjectRaw();
482 if (rawcpp ==
nullptr)
486 if (rawcpp !=
nullptr)
512 PyObject* mro = ((PyTypeObject*)klass)->tp_mro;
513 for (Py_ssize_t i = 1; mro && i < PyTuple_GET_SIZE(mro); ++i) {
514 PyObject* base = PyTuple_GET_ITEM(mro, i);
520 !PyType_HasFeature((PyTypeObject*)base, Py_TPFLAGS_HEAPTYPE) ||
523 PyOperators* bops = ((
CPPClass*)base)->fOperators;
524 PyObject* bop = op == Py_EQ ? bops->fEq : bops->fNe;
525 if (bop && bop != Py_None) {
529 bop = op == Py_EQ ? bops->fNe : bops->fEq;
530 if (bop && bop != Py_None) {
541 bool asEq = (op == Py_EQ) != flipit;
549 const char* cppop = op == Py_EQ ?
"==" :
"!=";
550 PyCallable* pyfunc = FindBinaryOperator(self, obj, cppop);
565 if (!binop || binop == Py_None)
570 PyTuple_SET_ITEM(args, 0, obj);
586 int istrue = PyObject_IsTrue(
result);
601 if (clActual && clActual != klass) {
603 clActual, klass, address, -1 ,
true );
605 address = (
void*)((intptr_t)address +
offset);
611#define CPYRT_ORDERED_OPERATOR_STUB(op, ometh, label) \
613 PyCallable* pyfunc = \
614 Utility::FindBinaryOperator((PyObject*)self, other, #op); \
616 ometh = (PyObject*)CPPOverload_New(#label, pyfunc); \
632 if (op == Py_EQ || op == Py_NE) {
636 "\nComparison of C++ nullptr objects with `None` is no longer "
638 "\n\nPreviously, `None` was treated as equivalent to a null C++ "
640 "but this led to confusing behavior where `x == None` could be True "
641 "even though `x is None` was False."
642 "\n\nTo test whether a C++ object is null or not, check its truth "
645 "\nor use `x is None` to explicitly check for Python None."
648 PyErr_SetString(PyExc_TypeError, msg);
665 if ((Py_TYPE(self) == Py_TYPE(other) &&
666 self->GetObject() == ((
CPPInstance*)other)->GetObject())) {
673 bIsEq = addr1 && addr2 && (addr1 == addr2);
676 if ((op == Py_EQ && bIsEq) || (op == Py_NE && !bIsEq))
683 else if (op == Py_LT || op == Py_LE || op == Py_GT || op == Py_GE) {
705 PyErr_SetString(PyExc_NotImplementedError,
"");
709 return PyObject_CallFunctionObjArgs(meth, (
PyObject*)self, other,
nullptr);
712 Py_INCREF(Py_NotImplemented);
713 return Py_NotImplemented;
723 return PyBaseObject_Type.tp_repr((
PyObject*)self);
736 repr = PyUnicode_FromFormat(
737 const_cast<char*
>(
"<%s.%s object at %p held by %s at %p>"),
738 PyUnicode_AsUTF8(modname), clName.c_str(), self->
GetObject(),
741 repr = PyUnicode_FromFormat(
const_cast<char*
>(
"<%s.%s object at %p>"),
742 PyUnicode_AsUTF8(modname), clName.c_str(),
754 if (
sizeof(
unsigned long) >=
sizeof(
size_t))
755 return (Py_hash_t)PyLong_AsUnsignedLong(obj);
756 return (Py_hash_t)PyLong_AsUnsignedLongLong(obj);
778 bool isValid = PyMapping_HasKeyString(dct, (
char*)
"__call__");
781 PyObject* hashobj = PyObject_CallObject(hashcls,
nullptr);
789 PyObject_CallFunctionObjArgs(hashobj, (
PyObject*)self,
nullptr);
800 ((PyTypeObject*)Py_TYPE(self))->tp_hash = PyBaseObject_Type.tp_hash;
801 return PyBaseObject_Type.tp_hash((
PyObject*)self);
809 std::ostringstream s;
819 res = PyObject_CallFunctionObjArgs(lshift, pys, NULL);
821 res = PyObject_CallFunctionObjArgs(lshift, pys, pyobj, NULL);
828 return PyUnicode_FromString(s.str().c_str());
865 else if (pyname == (
PyObject*)0x01) {
882 }
else if (pyname == (
PyObject*)0x02) {
886 const std::string& pretty =
889 return PyUnicode_FromString(pretty.c_str());
893 PyObject* lshift = PyObject_GetAttr(
934 PyObject* OL = PyObject_GetItem(printValue, clName);
938 OL ? PyObject_CallFunctionObjArgs(OL, byref,
nullptr) :
nullptr;
946 if (PyUnicode_Check(pretty)) {
947 if (
const char* s = PyUnicode_AsUTF8(pretty))
953 pv = *(std::string*)((
CPPInstance*)pretty)->GetObject();
956 if (!pv.empty() && pv.find(
"@0x") == std::string::npos &&
957 pv !=
"{not representable}")
958 result = PyUnicode_FromString(pv.c_str());
983 long shouldown = PyLong_AsLong(
value);
984 if (shouldown == -1 && PyErr_Occurred()) {
985 PyErr_SetString(PyExc_ValueError,
986 "__python_owns__ should be either True or False");
998 (
char*)
"If true, python manages the life time of this object",
nullptr},
999 {(
char*)
nullptr,
nullptr,
nullptr,
nullptr,
nullptr}};
1002#define CPYRT_STUB_BODY(name, op) \
1003 bool previously_resolved_overload = (bool)meth; \
1006 PyCallable* pyfunc = Utility::FindBinaryOperator(left, right, #op); \
1008 meth = (PyObject*)CPPOverload_New(#name, pyfunc); \
1010 PyErr_SetString(PyExc_NotImplementedError, ""); \
1014 PyObject* res = PyObject_CallFunctionObjArgs(meth, cppobj, other, nullptr); \
1015 if (!res && previously_resolved_overload) { \
1018 PyCallable* pyfunc = Utility::FindBinaryOperator(left, right, #op); \
1020 ((CPPOverload*&)meth)->AdoptMethod(pyfunc); \
1022 PyErr_SetString(PyExc_NotImplementedError, ""); \
1026 res = PyObject_CallFunctionObjArgs(meth, cppobj, other, nullptr); \
1030#define CPYRT_OPERATOR_STUB(name, op, ometh) \
1031 static PyObject* op_##name##_stub(PyObject* left, PyObject* right) { \
1033 CPPClass* klass = (CPPClass*)Py_TYPE(left); \
1034 if (!klass->fOperators) \
1035 klass->fOperators = new Utility::PyOperators{}; \
1036 PyObject*& meth = ometh; \
1037 PyObject *cppobj = left, *other = right; \
1038 CPYRT_STUB_BODY(name, op) \
1041#define CPYRT_ASSOCIATIVE_OPERATOR_STUB(name, op, lmeth, rmeth) \
1042 static PyObject* op_##name##_stub(PyObject* left, PyObject* right) { \
1047 PyObject *cppobj, *other; \
1048 if (CPPInstance_Check(left)) { \
1049 klass = (CPPClass*)Py_TYPE(left); \
1050 if (!klass->fOperators) \
1051 klass->fOperators = new Utility::PyOperators{}; \
1055 } else if (CPPInstance_Check(right)) { \
1056 klass = (CPPClass*)Py_TYPE(right); \
1057 if (!klass->fOperators) \
1058 klass->fOperators = new Utility::PyOperators{}; \
1063 PyErr_SetString(PyExc_NotImplementedError, ""); \
1066 PyObject*& meth = *pmeth; \
1067 CPYRT_STUB_BODY(name, op) \
1070#define CPYRT_UNARY_OPERATOR(name, op, label) \
1071 static PyObject* op_##name##_stub(PyObject* pyobj) { \
1073 PyCallable* pyfunc = \
1074 Utility::FindUnaryOperator((PyObject*)Py_TYPE(pyobj), #op); \
1076 Utility::AddToClass((PyObject*)Py_TYPE(pyobj), #label, pyfunc)) \
1077 return PyObject_CallMethod(pyobj, (char*)#label, nullptr); \
1078 PyErr_SetString(PyExc_NotImplementedError, ""); \
1135 0)(
char*)
"cppjit.CPPInstance",
1153 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
1154 (
char*)
"cppjit object proxy (internal)",
#define CPYRT_UNARY_OPERATOR(name, op, label)
#define EXT_OBJECT(pyobj)
#define CPYRT_ASSOCIATIVE_OPERATOR_STUB(name, op, lmeth, rmeth)
#define SMART_TYPE(pyobj)
#define CPYRT_ORDERED_OPERATOR_STUB(op, ometh, label)
#define DATA_CACHE(pyobj)
#define CPYRT_OPERATOR_STUB(name, op, ometh)
#define DISPATCHPTR(pyobj)
#define ARRAY_SIZE(pyobj)
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t target
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
interop::TCppScope_t GetSmartIsA() const
void CastToArray(Py_ssize_t sz)
interop::TCppScope_t GetSmartUnderlyingType() const
PyObject_HEAD void * fObject
CPPInstance * Copy(void *cppinst, PyTypeObject *target=nullptr)
static PyCFunction & ReduceMethod()
void * GetExtendedObject()
void SetSmart(PyObject *smart_type)
interop::TCppScope_t ObjectIsA(bool check_smart=true) const
void SetDispatchPtr(void *)
CI_DatamemberCache_t & GetDatamemberCache()
Utility::PyOperators * fOperators
static bool RegisterPyObject(CPPInstance *pyobj, interop::TCppObject_t cppobj)
static bool UnregisterPyObject(CPPInstance *pyobj, PyObject *pyclass)
#define CPYRT_PYTYPE_TAIL
std::string extract_namespace(const std::string &name)
std::string ClassName(PyObject *pyobj)
PyCallable * FindBinaryOperator(PyObject *left, PyObject *right, const char *op, interop::TCppScope_t scope=interop::TCppScope_t{})
bool AddToClass(PyObject *pyclass, const char *label, PyCFunction cfunc, int flags=METH_VARARGS)
PyObject * GetClingPrintValue()
std::string ObjToString(interop::TCppScope_t, interop::TCppObject_t)
static PyObject * op_repr(CPPInstance *self)
static PyObject * op_pos_stub(PyObject *pyobj)
static void * cast_actual(void *obj)
static int op_setownership(CPPInstance *pyobj, PyObject *value, void *)
PyTypeObject CPPScope_Type
PyObject * gNullPtrObject
static PyObject * op_item(CPPInstance *self, Py_ssize_t idx)
PyTypeObject CPPInstance_Type
PyTypeObject CPPOverload_Type
static PyObject * op_reshape(CPPInstance *self, PyObject *shape)
static void op_dealloc(CPPInstance *pyobj)
static PySequenceMethods op_as_sequence
static PyObject * op_richcompare(CPPInstance *self, PyObject *other, int op)
void op_dealloc_nofree(CPPInstance *)
static int op_traverse(CPPInstance *, visitproc, void *)
static PyObject * op_invert_stub(PyObject *pyobj)
static PyObject * op_destruct(CPPInstance *self)
static Py_hash_t cpyrt_PyLong_AsHash_t(PyObject *obj)
static PyMethodDef op_methods[]
static PyObject * op_get_smartptr(CPPInstance *self)
PyObject * CreateScopeProxy(PyObject *, PyObject *args)
static CPPInstance * op_new(PyTypeObject *subtype, PyObject *, PyObject *)
static PyObject * op_div_stub(PyObject *left, PyObject *right)
static PyObject * op_sub_stub(PyObject *left, PyObject *right)
static bool ScopeFlagCheck(CPPInstance *self, CPPScope::EFlags flag)
static int op_clear(CPPInstance *pyobj)
std::vector< std::pair< ptrdiff_t, PyObject * > > CI_DatamemberCache_t
static PyObject * op_str_internal(PyObject *pyobj, PyObject *lshift, bool isBound)
static PyNumberMethods op_as_number
static PyObject * op_dispatch(PyObject *self, PyObject *args, PyObject *)
PyObject * BindCppObjectNoCast(interop::TCppObject_t object, interop::TCppScope_t klass, const unsigned flags=0)
static PyObject * eqneq_binop(CPPClass *klass, PyObject *self, PyObject *obj, int op)
static PyGetSetDef op_getset[]
static PyObject * op_getownership(CPPInstance *pyobj, void *)
static Py_hash_t op_hash(CPPInstance *self)
static void ScopeFlagSet(CPPInstance *self, CPPScope::EFlags flag)
bool CPPScope_Check(T *object)
static PyObject * op_add_stub(PyObject *left, PyObject *right)
bool CPPInstance_Check(T *object)
static PyObject * op_neg_stub(PyObject *pyobj)
CPPOverload * CPPOverload_New(const std::string &name, std::vector< PyCallable * > &methods)
static PyObject * op_mul_stub(PyObject *left, PyObject *right)
static int op_nonzero(CPPInstance *self)
PyObject * op_reduce(PyObject *self, PyObject *args)
static PyObject * op_str(CPPInstance *self)
TCppScope_t GetFullScope(const std::string &scope_name)
Cpp::ObjectRef TCppObject_t
void CallDestructor(TCppScope_t type, TCppObject_t self)
TCppScope_t GetActualClass(TCppScope_t klass, TCppObject_t obj)
void Destruct(TCppScope_t scope, TCppObject_t instance)
size_t SizeOf(TCppScope_t klass)
void * CallR(TCppMethod_t method, TCppObject_t self, size_t nargs, void *args)
TCppScope_t GetScope(const std::string &scope_name, TCppScope_t parent_scope=TCppScope_t{})
std::string GetFinalName(TCppScope_t type)
ptrdiff_t GetBaseOffset(TCppScope_t derived, TCppScope_t base, TCppObject_t address, int direction, bool rerror=false)
void Deallocate(TCppScope_t scope, TCppObject_t instance)
std::string GetScopedFinalName(TCppScope_t type)