Logo ROOT  
Reference Guide
CPPInstance.cxx
Go to the documentation of this file.
1// Bindings
2#include "CPyCppyy.h"
3#include "CPPInstance.h"
4#include "CPPScope.h"
5#include "CPPOverload.h"
6#include "MemoryRegulator.h"
7#include "ProxyWrappers.h"
8#include "PyStrings.h"
9#include "TypeManip.h"
10#include "Utility.h"
11
13
14// Standard
15#include <algorithm>
16#include <sstream>
17
18
19//______________________________________________________________________________
20// Python-side proxy objects
21// =========================
22//
23// C++ objects are represented in Python by CPPInstances, which encapsulate
24// them using either a pointer (normal), pointer-to-pointer (kIsReference set),
25// or as an owned value (kIsValue set). Objects held as reference are never
26// owned, otherwise the object is owned if kIsOwner is set.
27//
28// In addition to encapsulation, CPPInstance offers rudimentary comparison
29// operators (based on pointer value and class comparisons); stubs (with lazy
30// lookups) for numeric operators; and a representation that prints the C++
31// pointer values, rather than the PyObject* ones as is the default.
32//
33// Smart pointers have the underlying type as the Python type, but store the
34// pointer to the smart pointer. They carry a pointer to the Python-sode smart
35// class for dereferencing to get to the actual instance pointer.
36
37
38//- private helpers ----------------------------------------------------------
39namespace {
40
41// Several specific use cases require extra data in a CPPInstance, but can not
42// be a new type. E.g. cross-inheritance derived types are by definition added
43// a posterio, and caching of datamembers is up to the datamember, not the
44// instance type. To not have normal use of CPPInstance take extra memory, this
45// extended data can slot in place of fObject for those use cases.
46
47struct ExtendedData {
48 ExtendedData() : fObject(nullptr), fSmartClass(nullptr), fTypeSize(0), fLastState(nullptr), fDispatchPtr(nullptr) {}
49 ~ExtendedData() {
50 for (auto& pc : fDatamemberCache)
51 Py_XDECREF(pc.second);
52 fDatamemberCache.clear();
53 }
54
55// the original object reference it replaces (Note: has to be first data member, see usage
56// in GetObjectRaw(), e.g. for ptr-ptr passing)
57 void* fObject;
58
59// for smart pointer types
60 CPyCppyy::CPPSmartClass* fSmartClass;
61 size_t fTypeSize;
62 void* fLastState;
63
64// for caching expensive-to-create data member representations
65 CPyCppyy::CI_DatamemberCache_t fDatamemberCache;
66
67// for back-referencing from Python-derived instances
68 CPyCppyy::DispatchPtr* fDispatchPtr;
69};
70
71} // unnamed namespace
72
73#define EXT_OBJECT(pyobj) ((ExtendedData*)((pyobj)->fObject))->fObject
74#define SMART_CLS(pyobj) ((ExtendedData*)((pyobj)->fObject))->fSmartClass
75#define SMART_TYPE(pyobj) SMART_CLS(pyobj)->fCppType
76#define DISPATCHPTR(pyobj) ((ExtendedData*)((pyobj)->fObject))->fDispatchPtr
77#define DATA_CACHE(pyobj) ((ExtendedData*)((pyobj)->fObject))->fDatamemberCache
78
80 if (fFlags & kIsExtended)
81 return;
82 void* obj = fObject;
83 fObject = (void*)new ExtendedData{};
84 EXT_OBJECT(this) = obj;
86}
87
89{
90 if (IsSmart()) {
91 // We get the raw pointer from the smart pointer each time, in case it has
92 // changed or has been freed.
93 return Cppyy::CallR(SMART_CLS(this)->fDereferencer, EXT_OBJECT(this), 0, nullptr);
94 }
95 return EXT_OBJECT(this);
96}
97
98
99//- public methods -----------------------------------------------------------
101{
102// create a fresh instance; args and kwds are not used by op_new (see below)
103 PyObject* self = (PyObject*)this;
104 PyTypeObject* pytype = Py_TYPE(self);
105 PyObject* newinst = pytype->tp_new(pytype, nullptr, nullptr);
106
107// set the C++ instance as given
108 ((CPPInstance*)newinst)->fObject = cppinst;
109
110// look for user-provided __cpp_copy__ (not reusing __copy__ b/c of differences
111// in semantics: need to pass in the new instance) ...
112 PyObject* cpy = PyObject_GetAttrString(self, (char*)"__cpp_copy__");
113 if (cpy && PyCallable_Check(cpy)) {
114 PyObject* args = PyTuple_New(1);
115 Py_INCREF(newinst);
116 PyTuple_SET_ITEM(args, 0, newinst);
117 PyObject* res = PyObject_CallObject(cpy, args);
118 Py_DECREF(args);
119 Py_DECREF(cpy);
120 if (res) {
121 Py_DECREF(res);
122 return (CPPInstance*)newinst;
123 }
124
125 // error already set, but need to return nullptr
126 Py_DECREF(newinst);
127 return nullptr;
128 } else if (cpy)
129 Py_DECREF(cpy);
130 else
131 PyErr_Clear();
132
133// ... otherwise, shallow copy any Python-side dictionary items
134 PyObject* selfdct = PyObject_GetAttr(self, PyStrings::gDict);
135 PyObject* newdct = PyObject_GetAttr(newinst, PyStrings::gDict);
136 bool bMergeOk = PyDict_Merge(newdct, selfdct, 1) == 0;
137 Py_DECREF(newdct);
138 Py_DECREF(selfdct);
139
140 if (!bMergeOk) {
141 // presume error already set
142 Py_DECREF(newinst);
143 return nullptr;
144 }
145
147 return (CPPInstance*)newinst;
148}
149
150
151//----------------------------------------------------------------------------
153{
154 fFlags |= kIsOwner;
155 if ((fFlags & kIsExtended) && DISPATCHPTR(this))
156 DISPATCHPTR(this)->PythonOwns();
157}
158
159//----------------------------------------------------------------------------
161{
162 fFlags &= ~kIsOwner;
163 if ((fFlags & kIsExtended) && DISPATCHPTR(this))
164 DISPATCHPTR(this)->CppOwns();
165}
166
167//----------------------------------------------------------------------------
169{
170 CreateExtension();
171 Py_INCREF(smart_type);
172 SMART_CLS(this) = (CPPSmartClass*)smart_type;
173 fFlags |= kIsSmartPtr;
174}
175
176//----------------------------------------------------------------------------
178{
179 if (!IsSmart()) return (Cppyy::TCppType_t)0;
180 return SMART_TYPE(this);
181}
182
183//----------------------------------------------------------------------------
185{
186// Return the cache for expensive data objects (and make extended as necessary)
187 CreateExtension();
188 return DATA_CACHE(this);
189}
190
191//----------------------------------------------------------------------------
193{
194// Set up the dispatch pointer for memory management
195 CreateExtension();
196 DISPATCHPTR(this) = (DispatchPtr*)ptr;
197}
198
199
200//----------------------------------------------------------------------------
202// Destroy the held C++ object, if owned; does not deallocate the proxy.
203
204 Cppyy::TCppType_t klass = pyobj->ObjectIsA(false /* check_smart */);
205 void*& cppobj = pyobj->GetObjectRaw();
206
209
210 if (pyobj->fFlags & CPPInstance::kIsOwner) {
211 if (pyobj->fFlags & CPPInstance::kIsValue) {
212 Cppyy::CallDestructor(klass, cppobj);
213 Cppyy::Deallocate(klass, cppobj);
214 } else {
215 if (cppobj) Cppyy::Destruct(klass, cppobj);
216 }
217 }
218 cppobj = nullptr;
219
220 if (pyobj->IsExtended()) delete (ExtendedData*)pyobj->fObject;
222}
223
224
225namespace CPyCppyy {
226
227//= CPyCppyy object proxy null-ness checking =================================
228static int op_nonzero(CPPInstance* self)
229{
230// Null of the proxy is determined by null-ness of the held C++ object.
231 if (!self->GetObject())
232 return 0;
233
234// If the object is valid, then the normal Python behavior is to allow __len__
235// to determine truth. However, that function is defined in typeobject.c and only
236// installed if tp_as_number exists w/o the nb_nonzero/nb_bool slot filled in, so
237// it can not be called directly. Instead, since we're only ever dealing with
238// CPPInstance derived objects, ignore length from sequence or mapping and call
239// the __len__ method, if any, directly.
240
241 PyObject* pylen = PyObject_CallMethodObjArgs((PyObject*)self, PyStrings::gLen, NULL);
242 if (!pylen) {
243 PyErr_Clear();
244 return 1; // since it's still a valid object
245 }
246
247 int result = PyObject_IsTrue(pylen);
248 Py_DECREF(pylen);
249 return result;
250}
251
252//= CPyCppyy object explicit destruction =====================================
254{
255// User access to force deletion of the object. Needed in case of a true
256// garbage collector (like in PyPy), to allow the user control over when
257// the C++ destructor is called. This method requires that the C++ object
258// is owned (no-op otherwise).
259 op_dealloc_nofree(self);
261}
262
263//= CPyCppyy object dispatch support =========================================
264static PyObject* op_dispatch(PyObject* self, PyObject* args, PyObject* /* kdws */)
265{
266// User-side __dispatch__ method to allow selection of a specific overloaded
267// method. The actual selection is in the __overload__() method of CPPOverload.
268 PyObject *mname = nullptr, *sigarg = nullptr;
269 if (!PyArg_ParseTuple(args, const_cast<char*>("O!O!:__dispatch__"),
270 &CPyCppyy_PyText_Type, &mname, &CPyCppyy_PyText_Type, &sigarg))
271 return nullptr;
272
273// get the named overload
274 PyObject* pymeth = PyObject_GetAttr(self, mname);
275 if (!pymeth)
276 return nullptr;
277
278// get the '__overload__' method to allow overload selection
279 PyObject* pydisp = PyObject_GetAttrString(pymeth, const_cast<char*>("__overload__"));
280 if (!pydisp) {
281 Py_DECREF(pymeth);
282 return nullptr;
283 }
284
285// finally, call dispatch to get the specific overload
286 PyObject* oload = PyObject_CallFunctionObjArgs(pydisp, sigarg, nullptr);
287 Py_DECREF(pydisp);
288 Py_DECREF(pymeth);
289 return oload;
290}
291
292//= CPyCppyy smart pointer support ===========================================
294{
295 if (!self->IsSmart()) {
296 // TODO: more likely should raise
298 }
299
301}
302
303
304//----------------------------------------------------------------------------
305static PyMethodDef op_methods[] = {
306 {(char*)"__destruct__", (PyCFunction)op_destruct, METH_NOARGS, nullptr},
307 {(char*)"__dispatch__", (PyCFunction)op_dispatch, METH_VARARGS,
308 (char*)"dispatch to selected overload"},
309 {(char*)"__smartptr__", (PyCFunction)op_get_smartptr, METH_NOARGS,
310 (char*)"get associated smart pointer, if any"},
311 {(char*)nullptr, nullptr, 0, nullptr}
312};
313
314
315//= CPyCppyy object proxy construction/destruction ===========================
316static CPPInstance* op_new(PyTypeObject* subtype, PyObject*, PyObject*)
317{
318// Create a new object proxy (holder only).
319 CPPInstance* pyobj = (CPPInstance*)subtype->tp_alloc(subtype, 0);
320 pyobj->fObject = nullptr;
322
323 return pyobj;
324}
325
326//----------------------------------------------------------------------------
327static void op_dealloc(CPPInstance* pyobj)
328{
329// Remove (Python-side) memory held by the object proxy.
330 PyObject_GC_UnTrack((PyObject*)pyobj);
331 op_dealloc_nofree(pyobj);
332 PyObject_GC_Del((PyObject*)pyobj);
333}
334
335//----------------------------------------------------------------------------
336static int op_clear(CPPInstance* pyobj)
337{
338// Garbage collector clear of held python member objects; this is a good time
339// to safely remove this object from the memory regulator.
342
343 return 0;
344}
345
346//----------------------------------------------------------------------------
347static inline PyObject* eqneq_binop(CPPClass* klass, PyObject* self, PyObject* obj, int op)
348{
349 using namespace Utility;
350
351 if (!klass->fOperators)
352 klass->fOperators = new PyOperators{};
353
354 bool flipit = false;
355 PyObject* binop = op == Py_EQ ? klass->fOperators->fEq : klass->fOperators->fNe;
356 if (!binop) {
357 const char* cppop = op == Py_EQ ? "==" : "!=";
358 PyCallable* pyfunc = FindBinaryOperator(self, obj, cppop);
359 if (pyfunc) binop = (PyObject*)CPPOverload_New(cppop, pyfunc);
360 else {
361 Py_INCREF(Py_None);
362 binop = Py_None;
363 }
364 // sets the operator to Py_None if not found, indicating that search was done
365 if (op == Py_EQ) klass->fOperators->fEq = binop;
366 else klass->fOperators->fNe = binop;
367 }
368
369 if (binop == Py_None) { // can try !== or !!= as alternatives
370 binop = op == Py_EQ ? klass->fOperators->fNe : klass->fOperators->fEq;
371 if (binop && binop != Py_None) flipit = true;
372 }
373
374 if (!binop || binop == Py_None) return nullptr;
375
376 PyObject* args = PyTuple_New(1);
377 Py_INCREF(obj); PyTuple_SET_ITEM(args, 0, obj);
378// since this overload is "ours", don't have to worry about rebinding
379 ((CPPOverload*)binop)->fSelf = (CPPInstance*)self;
380 PyObject* result = CPPOverload_Type.tp_call(binop, args, nullptr);
381 ((CPPOverload*)binop)->fSelf = nullptr;
382 Py_DECREF(args);
383
384 if (!result) {
385 PyErr_Clear();
386 return nullptr;
387 }
388
389// successful result, but may need to reverse the outcome
390 if (!flipit) return result;
391
392 int istrue = PyObject_IsTrue(result);
393 Py_DECREF(result);
394 if (istrue) {
396 }
398}
399
400static PyObject* op_richcompare(CPPInstance* self, PyObject* other, int op)
401{
402// Rich set of comparison objects; only equals and not-equals are defined.
403 if (op != Py_EQ && op != Py_NE) {
404 Py_INCREF(Py_NotImplemented);
405 return Py_NotImplemented;
406 }
407
408// special case for None to compare True to a null-pointer
409 if ((PyObject*)other == Py_None && !self->fObject) {
410 if (op == Py_EQ) { Py_RETURN_TRUE; }
412 }
413
414// use C++-side operators if available
415 PyObject* result = eqneq_binop((CPPClass*)Py_TYPE(self), (PyObject*)self, other, op);
416 if (!result && CPPInstance_Check(other))
417 result = eqneq_binop((CPPClass*)Py_TYPE(other), other, (PyObject*)self, op);
418 if (result) return result;
419
420// default behavior: type + held pointer value defines identity (covers if
421// other is not actually an CPPInstance, as ob_type will be unequal)
422 bool bIsEq = false;
423 if (Py_TYPE(self) == Py_TYPE(other) && \
424 self->GetObject() == ((CPPInstance*)other)->GetObject())
425 bIsEq = true;
426
427 if ((op == Py_EQ && bIsEq) || (op == Py_NE && !bIsEq)) {
429 }
431}
432
433//----------------------------------------------------------------------------
435{
436// Build a representation string of the object proxy that shows the address
437// of the C++ object that is held, as well as its type.
438 PyObject* pyclass = (PyObject*)Py_TYPE(self);
439 PyObject* modname = PyObject_GetAttr(pyclass, PyStrings::gModule);
440
441 Cppyy::TCppType_t klass = self->ObjectIsA();
442 std::string clName = klass ? Cppyy::GetFinalName(klass) : "<unknown>";
444 clName.append("*");
445
446 PyObject* repr = nullptr;
447 if (self->IsSmart()) {
448 std::string smartPtrName = Cppyy::GetScopedFinalName(SMART_TYPE(self));
450 const_cast<char*>("<%s.%s object at %p held by %s at %p>"),
451 CPyCppyy_PyText_AsString(modname), clName.c_str(),
452 self->GetObject(), smartPtrName.c_str(), self->GetObjectRaw());
453 } else {
454 repr = CPyCppyy_PyText_FromFormat(const_cast<char*>("<%s.%s object at %p>"),
455 CPyCppyy_PyText_AsString(modname), clName.c_str(), self->GetObject());
456 }
457
458 Py_DECREF(modname);
459 return repr;
460}
461
462//----------------------------------------------------------------------------
464{
465// Cannot use PyLong_AsSize_t here, as it cuts of at PY_SSIZE_T_MAX, which is
466// only half of the max of std::size_t returned by the hash.
467 if (sizeof(unsigned long) >= sizeof(size_t))
468 return (Py_hash_t)PyLong_AsUnsignedLong(obj);
469 return (Py_hash_t)PyLong_AsUnsignedLongLong(obj);
470}
471
473{
474// Try to locate an std::hash for this type and use that if it exists
475 CPPClass* klass = (CPPClass*)Py_TYPE(self);
476 if (klass->fOperators && klass->fOperators->fHash) {
477 Py_hash_t h = 0;
478 PyObject* hashval = PyObject_CallFunctionObjArgs(klass->fOperators->fHash, (PyObject*)self, nullptr);
479 if (hashval) {
480 h = CPyCppyy_PyLong_AsHash_t(hashval);
481 Py_DECREF(hashval);
482 }
483 return h;
484 }
485
486 Cppyy::TCppScope_t stdhash = Cppyy::GetScope("std::hash<"+Cppyy::GetScopedFinalName(self->ObjectIsA())+">");
487 if (stdhash) {
488 PyObject* hashcls = CreateScopeProxy(stdhash);
489 PyObject* dct = PyObject_GetAttr(hashcls, PyStrings::gDict);
490 bool isValid = PyMapping_HasKeyString(dct, (char*)"__call__");
491 Py_DECREF(dct);
492 if (isValid) {
493 PyObject* hashobj = PyObject_CallObject(hashcls, nullptr);
494 if (!klass->fOperators) klass->fOperators = new Utility::PyOperators{};
495 klass->fOperators->fHash = hashobj;
496 Py_DECREF(hashcls);
497
498 Py_hash_t h = 0;
499 PyObject* hashval = PyObject_CallFunctionObjArgs(hashobj, (PyObject*)self, nullptr);
500 if (hashval) {
501 h = CPyCppyy_PyLong_AsHash_t(hashval);
502 Py_DECREF(hashval);
503 }
504 return h;
505 }
506 Py_DECREF(hashcls);
507 }
508
509// if not valid, simply reset the hash function so as to not kill performance
510 ((PyTypeObject*)Py_TYPE(self))->tp_hash = PyBaseObject_Type.tp_hash;
511 return PyBaseObject_Type.tp_hash((PyObject*)self);
512}
513
514//----------------------------------------------------------------------------
515static PyObject* op_str_internal(PyObject* pyobj, PyObject* lshift, bool isBound)
516{
517 static Cppyy::TCppScope_t sOStringStreamID = Cppyy::GetScope("std::ostringstream");
518 std::ostringstream s;
519 PyObject* pys = BindCppObjectNoCast(&s, sOStringStreamID);
520 PyObject* res;
521 if (isBound) res = PyObject_CallFunctionObjArgs(lshift, pys, NULL);
522 else res = PyObject_CallFunctionObjArgs(lshift, pys, pyobj, NULL);
523 Py_DECREF(pys);
524 Py_DECREF(lshift);
525 if (res) {
526 Py_DECREF(res);
527 return CPyCppyy_PyText_FromString(s.str().c_str());
528 }
529 PyErr_Clear();
530 return nullptr;
531}
532
534{
535#ifndef _WIN64
536// Forward to C++ insertion operator if available, otherwise forward to repr.
537 PyObject* result = nullptr;
538 PyObject* pyobj = (PyObject*)self;
539 PyObject* lshift = PyObject_GetAttr(pyobj, PyStrings::gLShift);
540 if (lshift) result = op_str_internal(pyobj, lshift, true);
541
542 if (!result) {
543 PyErr_Clear();
544 PyObject* pyclass = (PyObject*)Py_TYPE(pyobj);
545 lshift = PyObject_GetAttr(pyclass, PyStrings::gLShiftC);
546 if (!lshift) {
547 PyErr_Clear();
548 // attempt lazy install of global operator<<(ostream&)
549 std::string rcname = Utility::ClassName(pyobj);
551 PyCallable* pyfunc = Utility::FindBinaryOperator("std::ostream", rcname, "<<", rnsID);
552 if (pyfunc) {
553 Utility::AddToClass(pyclass, "__lshiftc__", pyfunc);
554 lshift = PyObject_GetAttr(pyclass, PyStrings::gLShiftC);
555 } else
556 PyType_Type.tp_setattro(pyclass, PyStrings::gLShiftC, Py_None);
557 } else if (lshift == Py_None) {
558 Py_DECREF(lshift);
559 lshift = nullptr;
560 }
561 if (lshift) result = op_str_internal(pyobj, lshift, false);
562 }
563
564 if (result)
565 return result;
566#endif //!_WIN64
567
568 return op_repr(self);
569}
570
571//-----------------------------------------------------------------------------
573{
574 return PyBool_FromLong((long)(pyobj->fFlags & CPPInstance::kIsOwner));
575}
576
577//-----------------------------------------------------------------------------
578static int op_setownership(CPPInstance* pyobj, PyObject* value, void*)
579{
580// Set the ownership (True is python-owns) for the given object.
581 long shouldown = PyLong_AsLong(value);
582 if (shouldown == -1 && PyErr_Occurred()) {
583 PyErr_SetString(PyExc_ValueError, "__python_owns__ should be either True or False");
584 return -1;
585 }
586
587 (bool)shouldown ? pyobj->PythonOwns() : pyobj->CppOwns();
588
589 return 0;
590}
591
592
593//-----------------------------------------------------------------------------
594static PyGetSetDef op_getset[] = {
595 {(char*)"__python_owns__", (getter)op_getownership, (setter)op_setownership,
596 (char*)"If true, python manages the life time of this object", nullptr},
597 {(char*)nullptr, nullptr, nullptr, nullptr, nullptr}
598};
599
600
601//= CPyCppyy type number stubs to allow dynamic overrides =====================
602#define CPYCPPYY_STUB_BODY(name, op) \
603 if (!meth) { \
604 PyErr_Clear(); \
605 PyCallable* pyfunc = Utility::FindBinaryOperator(left, right, #op); \
606 if (pyfunc) meth = (PyObject*)CPPOverload_New(#name, pyfunc); \
607 else { \
608 PyErr_SetString(PyExc_NotImplementedError, ""); \
609 return nullptr; \
610 } \
611 } \
612 PyObject* res = PyObject_CallFunctionObjArgs(meth, cppobj, other, nullptr);\
613 if (!res) { \
614 /* try again, in case there is a better overload out there */ \
615 PyErr_Clear(); \
616 PyCallable* pyfunc = Utility::FindBinaryOperator(left, right, #op); \
617 if (pyfunc) ((CPPOverload*&)meth)->AdoptMethod(pyfunc); \
618 else { \
619 PyErr_SetString(PyExc_NotImplementedError, ""); \
620 return nullptr; \
621 } \
622 /* use same overload with newly added function */ \
623 res = PyObject_CallFunctionObjArgs(meth, cppobj, other, nullptr); \
624 } \
625 return res;
626
627
628#define CPYCPPYY_OPERATOR_STUB(name, op, ometh) \
629static PyObject* op_##name##_stub(PyObject* left, PyObject* right) \
630{ \
631/* placeholder to lazily install and forward to 'ometh' if available */ \
632 CPPClass* klass = (CPPClass*)Py_TYPE(left); \
633 if (!klass->fOperators) klass->fOperators = new Utility::PyOperators{}; \
634 PyObject*& meth = ometh; \
635 PyObject *cppobj = left, *other = right; \
636 CPYCPPYY_STUB_BODY(name, op) \
637}
638
639#define CPYCPPYY_ASSOCIATIVE_OPERATOR_STUB(name, op, lmeth, rmeth) \
640static PyObject* op_##name##_stub(PyObject* left, PyObject* right) \
641{ \
642/* placeholder to lazily install and forward do '(l/r)meth' if available */ \
643 CPPClass* klass; PyObject** pmeth; \
644 PyObject *cppobj, *other; \
645 if (CPPInstance_Check(left)) { \
646 klass = (CPPClass*)Py_TYPE(left); \
647 if (!klass->fOperators) klass->fOperators = new Utility::PyOperators{};\
648 pmeth = &lmeth; cppobj = left; other = right; \
649 } else if (CPPInstance_Check(right)) { \
650 klass = (CPPClass*)Py_TYPE(right); \
651 if (!klass->fOperators) klass->fOperators = new Utility::PyOperators{};\
652 pmeth = &rmeth; cppobj = right; other = left; \
653 } else { \
654 PyErr_SetString(PyExc_NotImplementedError, ""); \
655 return nullptr; \
656 } \
657 PyObject*& meth = *pmeth; \
658 CPYCPPYY_STUB_BODY(name, op) \
659}
660
661#define CPYCPPYY_UNARY_OPERATOR(name, op, label) \
662static PyObject* op_##name##_stub(PyObject* pyobj) \
663{ \
664/* placeholder to lazily install unary operators */ \
665 PyCallable* pyfunc = Utility::FindUnaryOperator((PyObject*)Py_TYPE(pyobj), #op);\
666 if (pyfunc && Utility::AddToClass((PyObject*)Py_TYPE(pyobj), #label, pyfunc))\
667 return PyObject_CallMethod(pyobj, (char*)#label, nullptr); \
668 PyErr_SetString(PyExc_NotImplementedError, ""); \
669 return nullptr; \
670}
671
672CPYCPPYY_ASSOCIATIVE_OPERATOR_STUB(add, +, klass->fOperators->fLAdd, klass->fOperators->fRAdd)
673CPYCPPYY_OPERATOR_STUB( sub, -, klass->fOperators->fSub)
674CPYCPPYY_ASSOCIATIVE_OPERATOR_STUB(mul, *, klass->fOperators->fLMul, klass->fOperators->fRMul)
675CPYCPPYY_OPERATOR_STUB( div, /, klass->fOperators->fDiv)
676CPYCPPYY_UNARY_OPERATOR(neg, -, __neg__)
677CPYCPPYY_UNARY_OPERATOR(pos, +, __pos__)
678CPYCPPYY_UNARY_OPERATOR(invert, ~, __invert__)
679
680//-----------------------------------------------------------------------------
681static PyNumberMethods op_as_number = {
682 (binaryfunc)op_add_stub, // nb_add
683 (binaryfunc)op_sub_stub, // nb_subtract
684 (binaryfunc)op_mul_stub, // nb_multiply
685#if PY_VERSION_HEX < 0x03000000
686 (binaryfunc)op_div_stub, // nb_divide
687#endif
688 0, // nb_remainder
689 0, // nb_divmod
690 0, // nb_power
691 (unaryfunc)op_neg_stub, // nb_negative
692 (unaryfunc)op_pos_stub, // nb_positive
693 0, // nb_absolute
694 (inquiry)op_nonzero, // nb_bool (nb_nonzero in p2)
695 (unaryfunc)op_invert_stub, // nb_invert
696 0, // nb_lshift
697 0, // nb_rshift
698 0, // nb_and
699 0, // nb_xor
700 0, // nb_or
701#if PY_VERSION_HEX < 0x03000000
702 0, // nb_coerce
703#endif
704 0, // nb_int
705 0, // nb_long (nb_reserved in p3)
706 0, // nb_float
707#if PY_VERSION_HEX < 0x03000000
708 0, // nb_oct
709 0, // nb_hex
710#endif
711 0, // nb_inplace_add
712 0, // nb_inplace_subtract
713 0, // nb_inplace_multiply
714#if PY_VERSION_HEX < 0x03000000
715 0, // nb_inplace_divide
716#endif
717 0, // nb_inplace_remainder
718 0, // nb_inplace_power
719 0, // nb_inplace_lshift
720 0, // nb_inplace_rshift
721 0, // nb_inplace_and
722 0, // nb_inplace_xor
723 0 // nb_inplace_or
724#if PY_VERSION_HEX >= 0x02020000
725 , 0 // nb_floor_divide
726#if PY_VERSION_HEX < 0x03000000
727 , 0 // nb_true_divide
728#else
729 , (binaryfunc)op_div_stub // nb_true_divide
730#endif
731 , 0 // nb_inplace_floor_divide
732 , 0 // nb_inplace_true_divide
733#endif
734#if PY_VERSION_HEX >= 0x02050000
735 , 0 // nb_index
736#endif
737#if PY_VERSION_HEX >= 0x03050000
738 , 0 // nb_matrix_multiply
739 , 0 // nb_inplace_matrix_multiply
740#endif
741};
742
743
744//= CPyCppyy object proxy type ===============================================
745PyTypeObject CPPInstance_Type = {
747 (char*)"cppyy.CPPInstance", // tp_name
748 sizeof(CPPInstance), // tp_basicsize
749 0, // tp_itemsize
750 (destructor)op_dealloc, // tp_dealloc
751 0, // tp_print
752 0, // tp_getattr
753 0, // tp_setattr
754 0, // tp_compare
755 (reprfunc)op_repr, // tp_repr
756 &op_as_number, // tp_as_number
757 0, // tp_as_sequence
758 0, // tp_as_mapping
759 (hashfunc)op_hash, // tp_hash
760 0, // tp_call
761 (reprfunc)op_str, // tp_str
762 0, // tp_getattro
763 0, // tp_setattro
764 0, // tp_as_buffer
765 Py_TPFLAGS_DEFAULT |
766 Py_TPFLAGS_BASETYPE |
767 Py_TPFLAGS_HAVE_GC |
768 Py_TPFLAGS_CHECKTYPES, // tp_flags
769 (char*)"cppyy object proxy (internal)", // tp_doc
770 0, // tp_traverse
771 (inquiry)op_clear, // tp_clear
772 (richcmpfunc)op_richcompare, // tp_richcompare
773 0, // tp_weaklistoffset
774 0, // tp_iter
775 0, // tp_iternext
776 op_methods, // tp_methods
777 0, // tp_members
778 op_getset, // tp_getset
779 0, // tp_base
780 0, // tp_dict
781 0, // tp_descr_get
782 0, // tp_descr_set
783 0, // tp_dictoffset
784 0, // tp_init
785 0, // tp_alloc
786 (newfunc)op_new, // tp_new
787 0, // tp_free
788 0, // tp_is_gc
789 0, // tp_bases
790 0, // tp_mro
791 0, // tp_cache
792 0, // tp_subclasses
793 0 // tp_weaklist
794#if PY_VERSION_HEX >= 0x02030000
795 , 0 // tp_del
796#endif
797#if PY_VERSION_HEX >= 0x02060000
798 , 0 // tp_version_tag
799#endif
800#if PY_VERSION_HEX >= 0x03040000
801 , 0 // tp_finalize
802#endif
803};
804
805} // namespace CPyCppyy
#define SMART_CLS(pyobj)
Definition: CPPInstance.cxx:74
#define CPYCPPYY_UNARY_OPERATOR(name, op, label)
#define EXT_OBJECT(pyobj)
Definition: CPPInstance.cxx:73
#define SMART_TYPE(pyobj)
Definition: CPPInstance.cxx:75
#define CPYCPPYY_OPERATOR_STUB(name, op, ometh)
#define DATA_CACHE(pyobj)
Definition: CPPInstance.cxx:77
#define DISPATCHPTR(pyobj)
Definition: CPPInstance.cxx:76
#define CPYCPPYY_ASSOCIATIVE_OPERATOR_STUB(name, op, lmeth, rmeth)
#define Py_TYPE(ob)
Definition: CPyCppyy.h:209
#define Py_RETURN_TRUE
Definition: CPyCppyy.h:285
#define Py_RETURN_FALSE
Definition: CPyCppyy.h:289
#define CPyCppyy_PyText_AsString
Definition: CPyCppyy.h:97
long Py_hash_t
Definition: CPyCppyy.h:133
#define PyBool_FromLong
Definition: CPyCppyy.h:264
#define CPyCppyy_PyText_FromFormat
Definition: CPyCppyy.h:101
#define Py_RETURN_NONE
Definition: CPyCppyy.h:281
#define CPyCppyy_PyText_Type
Definition: CPyCppyy.h:115
#define CPyCppyy_PyText_FromString
Definition: CPyCppyy.h:102
#define PyVarObject_HEAD_INIT(type, size)
Definition: CPyCppyy.h:207
unsigned int fFlags
_object PyObject
Definition: PyMethodBase.h:41
#define h(i)
Definition: RSha256.hxx:106
Cppyy::TCppType_t GetSmartIsA() const
bool IsSmart() const
Definition: CPPInstance.h:56
CPPInstance * Copy(void *cppinst)
CI_DatamemberCache_t & GetDatamemberCache()
void SetSmart(PyObject *smart_type)
void *& GetObjectRaw()
Definition: CPPInstance.h:60
PyObject_HEAD void * fObject
Definition: CPPInstance.h:44
Cppyy::TCppType_t ObjectIsA(bool check_smart=true) const
Definition: CPPInstance.h:106
bool IsExtended() const
Definition: CPPInstance.h:55
void SetDispatchPtr(void *)
Utility::PyOperators * fOperators
Definition: CPPScope.h:56
static bool RegisterPyObject(CPPInstance *pyobj, void *cppobj)
static bool UnregisterPyObject(CPPInstance *pyobj, PyObject *pyclass)
PyObject * gDict
Definition: PyStrings.cxx:14
PyObject * gLShiftC
Definition: PyStrings.cxx:39
PyObject * gLShift
Definition: PyStrings.cxx:38
PyObject * gModule
Definition: PyStrings.cxx:24
std::string extract_namespace(const std::string &name)
Definition: TypeManip.cxx:159
PyCallable * FindBinaryOperator(PyObject *left, PyObject *right, const char *op, Cppyy::TCppScope_t scope=0)
Definition: Utility.cxx:280
bool AddToClass(PyObject *pyclass, const char *label, PyCFunction cfunc, int flags=METH_VARARGS)
Definition: Utility.cxx:169
std::string ClassName(PyObject *pyobj)
Definition: Utility.cxx:825
CPPOverload * CPPOverload_New(const std::string &name, std::vector< PyCallable * > &methods)
Definition: CPPOverload.h:91
PyTypeObject CPPInstance_Type
static PyObject * op_str_internal(PyObject *pyobj, PyObject *lshift, bool isBound)
static Py_hash_t CPyCppyy_PyLong_AsHash_t(PyObject *obj)
static int op_nonzero(CPPInstance *self)
static PyMethodDef op_methods[]
static PyObject * op_repr(CPPInstance *self)
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
Definition: CPPInstance.h:24
static int op_setownership(CPPInstance *pyobj, PyObject *value, void *)
static PyObject * eqneq_binop(CPPClass *klass, PyObject *self, PyObject *obj, int op)
static PyObject * op_getownership(CPPInstance *pyobj, void *)
static int op_clear(CPPInstance *pyobj)
void op_dealloc_nofree(CPPInstance *)
bool CPPInstance_Check(T *object)
Definition: CPPInstance.h:118
PyObject * CreateScopeProxy(Cppyy::TCppScope_t)
static PyGetSetDef op_getset[]
PyTypeObject CPPOverload_Type
static PyNumberMethods op_as_number
static PyObject * op_str(CPPInstance *self)
static void op_dealloc(CPPInstance *pyobj)
static Py_hash_t op_hash(CPPInstance *self)
static PyObject * op_dispatch(PyObject *self, PyObject *args, PyObject *)
PyTypeObject CPPScope_Type
Definition: CPPScope.cxx:613
static PyObject * op_get_smartptr(CPPInstance *self)
static CPPInstance * op_new(PyTypeObject *subtype, PyObject *, PyObject *)
static PyObject * op_destruct(CPPInstance *self)
TCppScope_t TCppType_t
Definition: cpp_cppyy.h:19
RPY_EXPORTED void * CallR(TCppMethod_t method, TCppObject_t self, size_t nargs, void *args)
RPY_EXPORTED void CallDestructor(TCppType_t type, TCppObject_t self)
RPY_EXPORTED std::string GetFinalName(TCppType_t type)
size_t TCppScope_t
Definition: cpp_cppyy.h:18
RPY_EXPORTED std::string GetScopedFinalName(TCppType_t type)
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
RPY_EXPORTED void Destruct(TCppType_t type, TCppObject_t instance)
RPY_EXPORTED void Deallocate(TCppType_t type, TCppObject_t instance)
static constexpr double s
static constexpr double pc