Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
Dispatcher.cxx
Go to the documentation of this file.
1// Bindings
2#include "CPyCppyy.h"
3#include "Dispatcher.h"
4#include "CPPScope.h"
5#include "PyStrings.h"
6#include "ProxyWrappers.h"
7#include "TypeManip.h"
8#include "Utility.h"
9
10// Standard
11#include <set>
12#include <sstream>
13
14
15//----------------------------------------------------------------------------
16static inline void InjectMethod(Cppyy::TCppMethod_t method, const std::string& mtCppName, std::ostringstream& code)
17{
18// inject implementation for an overridden method
19 using namespace CPyCppyy;
20
21// method declaration
22 std::string retType = Cppyy::GetMethodResultType(method);
23 code << " " << retType << " " << mtCppName << "(";
24
25// build out the signature with predictable formal names
27 std::vector<std::string> argtypes; argtypes.reserve(nArgs);
28 for (Cppyy::TCppIndex_t i = 0; i < nArgs; ++i) {
29 argtypes.push_back(Cppyy::GetMethodArgType(method, i));
30 if (i != 0) code << ", ";
31 code << argtypes.back() << " arg" << i;
32 }
33 code << ") ";
34 if (Cppyy::IsConstMethod(method)) code << "const ";
35 code << "{\n";
36
37// on destruction, the Python object may go first, in which case provide a diagnostic
38// warning (raising a PyException may not be possible as this could happen during
39// program shutdown); note that this means that the actual result will be the default
40// and the caller may need to act on that, but that's still an improvement over a
41// possible crash
42 code << " PyObject* iself = (PyObject*)_internal_self;\n"
43 " if (!iself || iself == Py_None) {\n"
44 " PyErr_Warn(PyExc_RuntimeWarning, (char*)\"Call attempted on deleted python-side proxy\");\n"
45 " return";
46 if (retType != "void") {
47 if (retType.back() != '*')
48 code << " " << CPyCppyy::TypeManip::remove_const(retType) << "{}";
49 else
50 code << " nullptr";
51 }
52 code << ";\n"
53 " }\n"
54 " Py_INCREF(iself);\n";
55
56// start actual function body
57 Utility::ConstructCallbackPreamble(retType, argtypes, code);
58
59// perform actual method call
60#if PY_VERSION_HEX < 0x03000000
61 code << " PyObject* mtPyName = PyString_FromString(\"" << mtCppName << "\");\n" // TODO: intern?
62#else
63 code << " PyObject* mtPyName = PyUnicode_FromString(\"" << mtCppName << "\");\n"
64#endif
65 " PyObject* pyresult = PyObject_CallMethodObjArgs(iself, mtPyName";
66 for (Cppyy::TCppIndex_t i = 0; i < nArgs; ++i)
67 code << ", pyargs[" << i << "]";
68 code << ", NULL);\n Py_DECREF(mtPyName);\n Py_DECREF(iself);\n";
69
70// close
71 Utility::ConstructCallbackReturn(retType, (int)nArgs, code);
72}
73
74//----------------------------------------------------------------------------
75namespace {
76 struct BaseInfo {
77 BaseInfo(Cppyy::TCppType_t t, std::string&& bn, std::string&& bns) :
78 btype(t), bname(bn), bname_scoped(bns) {}
80 std::string bname;
81 std::string bname_scoped;
82 };
83
84 typedef std::vector<BaseInfo> BaseInfos_t;
85 typedef std::vector<Cppyy::TCppMethod_t> Ctors_t;
86 typedef std::vector<Ctors_t> AllCtors_t;
87 typedef std::vector<std::pair<Cppyy::TCppMethod_t, size_t>> CtorInfos_t;
88} // unnamed namespace
89
91 const std::string& derivedName, const BaseInfos_t& base_infos, const AllCtors_t& ctors,
92 std::ostringstream& code, const CtorInfos_t& methods = CtorInfos_t{}, size_t idx = 0)
93{
94 if (idx < ctors.size()) {
95 for (const auto& method : ctors[idx]) {
96 size_t argsmin = (size_t)Cppyy::GetMethodReqArgs(method);
97 size_t argsmax = (size_t)Cppyy::GetMethodNumArgs(method);
98 for (size_t i = argsmin; i <= argsmax; ++i) {
99 CtorInfos_t methods1{methods};
100 methods1.emplace_back(method, i);
101 build_constructors(derivedName, base_infos, ctors, code, methods1, idx+1);
102 }
103 }
104 } else {
105 // this is as deep as we go; start writing
106 code << " " << derivedName << "(";
107
108 // declare arguments
109 std::vector<size_t> arg_tots; arg_tots.reserve(methods.size());
110 for (Ctors_t::size_type i = 0; i < methods.size(); ++i) {
111 const auto& cinfo = methods[i];
112 if (i != 0 && (arg_tots.back() || 1 < arg_tots.size())) code << ", ";
113 size_t nArgs = cinfo.second;
114 arg_tots.push_back(i == 0 ? nArgs : nArgs+arg_tots.back());
115
116 if (i != 0) code << "__cppyy_internal::Sep*";
117 size_t offset = (i != 0 ? arg_tots[i-1] : 0);
118 for (size_t j = 0; j < nArgs; ++j) {
119 if (i != 0 || j != 0) code << ", ";
120 code << Cppyy::GetMethodArgType(cinfo.first, j) << " a" << (j+offset);
121 }
122 }
123 code << ") : ";
124
125 // pass arguments to base constructors
126 for (BaseInfos_t::size_type i = 0; i < base_infos.size(); ++i) {
127 if (i != 0) code << ", ";
128 code << base_infos[i].bname << "(";
129 size_t first = (i != 0 ? arg_tots[i-1] : 0);
130 for (size_t j = first; j < arg_tots[i]; ++j) {
131 if (j != first) code << ", ";
132 bool isRValue = CPyCppyy::TypeManip::compound(\
133 Cppyy::GetMethodArgType(methods[i].first, j-first)) == "&&";
134 if (isRValue) code << "std::move(";
135 code << "a" << j;
136 if (isRValue) code << ")";
137 }
138 code << ")";
139 }
140 code << " {}\n";
141 }
142}
143
144namespace {
145
146using namespace Cppyy;
147
148static inline
149std::vector<TCppIndex_t> FindBaseMethod(TCppScope_t tbase, const std::string mtCppName)
150{
151// Recursively walk the inheritance tree to find the overloads of the named method
152 std::vector<TCppIndex_t> result;
153 result = GetMethodIndicesFromName(tbase, mtCppName);
154 if (result.empty()) {
155 for (TCppIndex_t ibase = 0; ibase < GetNumBases(tbase); ++ibase) {
156 TCppScope_t b = GetScope(GetBaseName(tbase, ibase));
157 result = FindBaseMethod(b, mtCppName);
158 if (!result.empty())
159 break;
160 }
161 }
162 return result;
163}
164
165} // unnamed namespace
166
167bool CPyCppyy::InsertDispatcher(CPPScope* klass, PyObject* bases, PyObject* dct, std::ostringstream& err)
168{
169// Scan all methods in dct and where it overloads base methods in klass, create
170// dispatchers on the C++ side. Then interject the dispatcher class.
171
172 if (!PyTuple_Check(bases) || !PyTuple_GET_SIZE(bases) || !dct || !PyDict_Check(dct)) {
173 err << "internal error: expected tuple of bases and proper dictionary";
174 return false;
175 }
176
177 if (!Utility::IncludePython()) {
178 err << "failed to include Python.h";
179 return false;
180 }
181
182// collect all bases, error checking the hierarchy along the way
183 const Py_ssize_t nBases = PyTuple_GET_SIZE(bases);
184 BaseInfos_t base_infos; base_infos.reserve(nBases);
185 for (Py_ssize_t ibase = 0; ibase < nBases; ++ibase) {
186 if (!CPPScope_Check(PyTuple_GET_ITEM(bases, ibase)))
187 continue;
188
189 Cppyy::TCppType_t basetype = ((CPPScope*)PyTuple_GET_ITEM(bases, ibase))->fCppType;
190
191 if (!basetype) {
192 err << "base class is incomplete";
193 break;
194 }
195
196 if (Cppyy::IsNamespace(basetype)) {
197 err << Cppyy::GetScopedFinalName(basetype) << " is a namespace";
198 break;
199 }
200
201 if (!Cppyy::HasVirtualDestructor(basetype)) {
202 const std::string& bname = Cppyy::GetScopedFinalName(basetype);
203 PyErr_Warn(PyExc_RuntimeWarning, (char*)("class \""+bname+"\" has no virtual destructor").c_str());
204 }
205
206 base_infos.emplace_back(
207 basetype, TypeManip::template_base(Cppyy::GetFinalName(basetype)), Cppyy::GetScopedFinalName(basetype));
208 }
209
210// TODO: check deep hierarchy for multiple inheritance
211 bool isDeepHierarchy = klass->fCppType && base_infos.front().btype != klass->fCppType;
212
213// once classes can be extended, should consider re-use; for now, since derived
214// python classes can differ in what they override, simply use different shims
215 static int counter = 0;
216 std::ostringstream osname;
217 osname << "Dispatcher" << ++counter;
218 const std::string& derivedName = osname.str();
219
220// generate proxy class with the relevant method dispatchers
221 std::ostringstream code;
222
223// start class declaration
224 code << "namespace __cppyy_internal {\n"
225 << "class " << derivedName << " : ";
226 for (BaseInfos_t::size_type ibase = 0; ibase < base_infos.size(); ++ibase) {
227 if (ibase != 0) code << ", ";
228 code << "public ::" << base_infos[ibase].bname_scoped;
229 }
230 code << " {\n";
231 if (!isDeepHierarchy)
232 code << "protected:\n CPyCppyy::DispatchPtr _internal_self;\n";
233 code << "public:\n";
234
235// add a virtual destructor for good measure, which is allowed to be "overridden" by
236// the conventional __destruct__ method (note that __del__ is always called, too, if
237// provided, but only when the Python object goes away; furthermore, if the Python
238// object goes before the C++ one, only __del__ is called)
239 if (PyMapping_HasKeyString(dct, (char*)"__destruct__")) {
240 code << " virtual ~" << derivedName << "() {\n"
241 " PyObject* iself = (PyObject*)_internal_self;\n"
242 " if (!iself || iself == Py_None)\n"
243 " return;\n" // safe, as destructor always returns void
244 " Py_INCREF(iself);\n"
245 " PyObject* mtPyName = PyUnicode_FromString(\"__destruct__\");\n"
246 " PyObject* pyresult = PyObject_CallMethodObjArgs(iself, mtPyName, NULL);\n"
247 " Py_DECREF(mtPyName);\n Py_DECREF(iself);\n";
248
249 // this being a destructor, print on exception rather than propagate using the
250 // magic C++ exception ...
251 code << " if (!pyresult) PyErr_Print();\n"
252 " else { Py_DECREF(pyresult); }\n"
253 " }\n";
254 } else
255 code << " virtual ~" << derivedName << "() {}\n";
256
257// methods: first collect all callables, then get overrides from base classes, for
258// those that are still missing, search the hierarchy
259 PyObject* clbs = PyDict_New();
260 PyObject* items = PyDict_Items(dct);
261 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(items); ++i) {
262 PyObject* value = PyTuple_GET_ITEM(PyList_GET_ITEM(items, i), 1);
263 if (PyCallable_Check(value))
264 PyDict_SetItem(clbs, PyTuple_GET_ITEM(PyList_GET_ITEM(items, i), 0), value);
265 }
266 Py_DECREF(items);
267 if (PyDict_DelItem(clbs, PyStrings::gInit) != 0)
268 PyErr_Clear();
269
270// protected methods and data need their access changed in the C++ trampoline and then
271// exposed on the Python side; so, collect their names as we go along
272 std::set<std::string> protected_names;
273
274// simple case: methods from current class (collect constructors along the way)
275 int has_default = 0, has_cctor = 0, has_ctors = 0, has_tmpl_ctors = 0;
276 AllCtors_t ctors{base_infos.size()};
277 for (BaseInfos_t::size_type ibase = 0; ibase < base_infos.size(); ++ibase) {
278 const auto& binfo = base_infos[ibase];
279
280 const Cppyy::TCppIndex_t nMethods = Cppyy::GetNumMethods(binfo.btype);
281 bool cctor_found = false, default_found = false, any_ctor_found = false;
282 for (Cppyy::TCppIndex_t imeth = 0; imeth < nMethods; ++imeth) {
283 Cppyy::TCppMethod_t method = Cppyy::GetMethod(binfo.btype, imeth);
284
285 if (Cppyy::IsConstructor(method)) {
286 any_ctor_found = true;
287 if (Cppyy::IsPublicMethod(method) || Cppyy::IsProtectedMethod(method)) {
289 if (nreq == 0) default_found = true;
290 else if (!cctor_found && nreq == 1) {
291 const std::string& argtype = Cppyy::GetMethodArgType(method, 0);
292 if (TypeManip::compound(argtype) == "&" && TypeManip::clean_type(argtype, false) == binfo.bname_scoped)
293 cctor_found = true;
294 }
295 ctors[ibase].push_back(method);
296 }
297 continue;
298 }
299
300 std::string mtCppName = Cppyy::GetMethodName(method);
301 PyObject* key = CPyCppyy_PyText_FromString(mtCppName.c_str());
302 int contains = PyDict_Contains(dct, key);
303 if (contains == -1) PyErr_Clear();
304 if (contains != 1) {
305 Py_DECREF(key);
306
307 // if the method is protected, we expose it through re-declaration and forwarding (using
308 // does not work here b/c there may be private overloads)
309 if (Cppyy::IsProtectedMethod(method)) {
310 protected_names.insert(mtCppName);
311
312 code << " " << Cppyy::GetMethodResultType(method) << " " << mtCppName << "(";
314 for (Cppyy::TCppIndex_t i = 0; i < nArgs; ++i) {
315 if (i != 0) code << ", ";
316 code << Cppyy::GetMethodArgType(method, i) << " arg" << i;
317 }
318 code << ") ";
319 if (Cppyy::IsConstMethod(method)) code << "const ";
320 code << "{\n return " << binfo.bname << "::" << mtCppName << "(";
321 for (Cppyy::TCppIndex_t i = 0; i < nArgs; ++i) {
322 if (i != 0) code << ", ";
323 code << "arg" << i;
324 }
325 code << ");\n }\n";
326 }
327
328 continue;
329 }
330
331 InjectMethod(method, mtCppName, code);
332
333 if (PyDict_DelItem(clbs, key) != 0)
334 PyErr_Clear(); // happens for overloads
335 Py_DECREF(key);
336 }
337
338 // support for templated ctors in single inheritance (TODO: also multi possible?)
339 if (base_infos.size() == 1) {
340 const Cppyy::TCppIndex_t nTemplMethods = Cppyy::GetNumTemplatedMethods(binfo.btype);
341 for (Cppyy::TCppIndex_t imeth = 0; imeth < nTemplMethods; ++imeth) {
342 if (Cppyy::IsTemplatedConstructor(binfo.btype, imeth)) {
343 any_ctor_found = true;
344 has_tmpl_ctors += 1;
345 break; // one suffices to map as argument packs are used
346 }
347 }
348 }
349
350 // count the cctors and default ctors to determine whether each base has one
351 if (cctor_found || (!cctor_found && !any_ctor_found)) has_cctor += 1;
352 if (default_found || (!default_found && !any_ctor_found)) has_default += 1;
353 if (any_ctor_found && !has_tmpl_ctors) has_ctors += 1;
354 }
355
356// try to locate left-overs in base classes
357 for (const auto& binfo : base_infos) {
358 if (PyDict_Size(clbs)) {
359 size_t nbases = Cppyy::GetNumBases(binfo.btype);
360 for (size_t ibase = 0; ibase < nbases; ++ibase) {
362 Cppyy::GetBaseName(binfo.btype, ibase));
363
364 PyObject* keys = PyDict_Keys(clbs);
365 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(keys); ++i) {
366 // TODO: should probably invert this looping; but that makes handling overloads clunky
367 PyObject* key = PyList_GET_ITEM(keys, i);
368 std::string mtCppName = CPyCppyy_PyText_AsString(key);
369 const auto& v = FindBaseMethod(tbase, mtCppName);
370 for (auto idx : v)
371 InjectMethod(Cppyy::GetMethod(tbase, idx), mtCppName, code);
372 if (!v.empty()) {
373 if (PyDict_DelItem(clbs, key) != 0) PyErr_Clear();
374 }
375 }
376 Py_DECREF(keys);
377 }
378 }
379 }
380 Py_DECREF(clbs);
381
382// constructors: build up from the argument types of the base class, for use by the Python
383// derived class (inheriting with/ "using" does not work b/c base class constructors may
384// have been deleted),
385 build_constructors(derivedName, base_infos, ctors, code);
386
387// for working with C++ templates, additional constructors are needed to make
388// sure the python object is properly carried, but they can only be generated
389// if the base class supports them
390 if (1 < nBases && (!has_ctors || has_default == nBases))
391 code << " " << derivedName << "() {}\n";
392 if (has_cctor == nBases) {
393 code << " " << derivedName << "(const " << derivedName << "& other) : ";
394 for (BaseInfos_t::size_type ibase = 0; ibase < base_infos.size(); ++ibase) {
395 if (ibase != 0) code << ", ";
396 code << base_infos[ibase].bname << "(other)";
397 }
398 if (!isDeepHierarchy)
399 code << ", _internal_self(other._internal_self, this)";
400 code << " {}\n";
401 }
402 if (has_tmpl_ctors && base_infos.size() == 1) {
403 // support for templated ctors in single inheritance (TODO: also multi possible?)
404 code << " template<typename ...Args>\n " << derivedName << "(Args... args) : "
405 << base_infos[0].bname << "(args...) {}\n";
406 }
407
408// destructor: default is fine
409
410// pull in data members that are protected
411 bool setPublic = false;
412 for (const auto& binfo : base_infos) {
413 Cppyy::TCppIndex_t nData = Cppyy::GetNumDatamembers(binfo.btype);
414 for (Cppyy::TCppIndex_t idata = 0; idata < nData; ++idata) {
415 if (Cppyy::IsProtectedData(binfo.btype, idata)) {
416 const std::string dm_name = Cppyy::GetDatamemberName(binfo.btype, idata);
417 if (dm_name != "_internal_self") {
418 const std::string& dname = Cppyy::GetDatamemberName(binfo.btype, idata);
419 protected_names.insert(dname);
420 if (!setPublic) {
421 code << "public:\n";
422 setPublic = true;
423 }
424 code << " using " << binfo.bname << "::" << dname << ";\n";
425 }
426 }
427 }
428 }
429
430// initialize the dispatch pointer for all direct bases that have one
431 BaseInfos_t::size_type disp_inited = 0;
432 code << "public:\n static void _init_dispatchptr(" << derivedName << "* inst, PyObject* self) {\n";
433 if (1 < base_infos.size()) {
434 for (const auto& binfo : base_infos) {
435 if (Cppyy::GetDatamemberIndex(binfo.btype, "_internal_self") != (Cppyy::TCppIndex_t)-1) {
436 code << " " << binfo.bname << "::_init_dispatchptr(inst, self);\n";
437 disp_inited += 1;
438 }
439 }
440 }
441// The dispatch initializer is only used in constructors, and C++ object start out
442// as owned by C++, with Python ownership explicitly set only later. To match, the
443// dispatch pointer needs to start out with a hard reference, i.e. C++ ownership of
444// the dispatch object. If the constructor has __creates__ set to True (default),
445// then a call to PythonOwns() will switch the hard ref to a weak ref, preventing
446// accidental circular references.
447 if (disp_inited != base_infos.size())
448 code << " new ((void*)&inst->_internal_self) CPyCppyy::DispatchPtr{self, true};\n";
449 code << " }";
450
451// provide an accessor to re-initialize after round-tripping from C++ (internal)
452 code << "\n static PyObject* _get_dispatch(" << derivedName << "* inst) {\n"
453 " PyObject* res = (PyObject*)inst->_internal_self;\n"
454 " Py_XINCREF(res); return res;\n }";
455
456// finish class declaration
457 code << "};\n}";
458
459// finally, compile the code
460 if (!Cppyy::Compile(code.str())) {
461 err << "failed to compile the dispatcher code";
462 return false;
463 }
464
465// keep track internally of the actual C++ type (this is used in
466// CPPConstructor to call the dispatcher's one instead of the base)
467 Cppyy::TCppScope_t disp = Cppyy::GetScope("__cppyy_internal::"+derivedName);
468 if (!disp) {
469 err << "failed to retrieve the internal dispatcher";
470 return false;
471 }
472 klass->fCppType = disp;
473
474// at this point, the dispatcher only lives in C++, as opposed to regular classes
475// that are part of the hierarchy in Python, so create it, which will cache it for
476// later use by e.g. the MemoryRegulator
477 unsigned int flags = (unsigned int)(klass->fFlags & CPPScope::kIsMultiCross);
478 PyObject* disp_proxy = CPyCppyy::CreateScopeProxy(disp, flags);
479 if (flags) ((CPPScope*)disp_proxy)->fFlags |= CPPScope::kIsMultiCross;
480 ((CPPScope*)disp_proxy)->fFlags |= CPPScope::kIsPython;
481
482// finally, to expose protected members, copy them over from the C++ dispatcher base
483// to the Python dictionary (the C++ dispatcher's Python proxy is not a base of the
484// Python class to keep the inheritance tree intact)
485 for (const auto& name : protected_names) {
486 PyObject* disp_dct = PyObject_GetAttr(disp_proxy, PyStrings::gDict);
487 PyObject* pyf = PyMapping_GetItemString(disp_dct, (char*)name.c_str());
488 if (pyf) {
489 PyObject_SetAttrString((PyObject*)klass, (char*)name.c_str(), pyf);
490 Py_DECREF(pyf);
491 }
492 Py_DECREF(disp_dct);
493 }
494
495 Py_XDECREF(disp_proxy);
496
497 return true;
498}
#define CPyCppyy_PyText_AsString
Definition CPyCppyy.h:76
#define CPyCppyy_PyText_FromString
Definition CPyCppyy.h:81
static void InjectMethod(Cppyy::TCppMethod_t method, const std::string &mtCppName, std::ostringstream &code)
static void build_constructors(const std::string &derivedName, const BaseInfos_t &base_infos, const AllCtors_t &ctors, std::ostringstream &code, const CtorInfos_t &methods=CtorInfos_t{}, size_t idx=0)
_object PyObject
#define b(i)
Definition RSha256.hxx:100
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 result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
char name[80]
Definition TGX11.cxx:110
uint32_t fFlags
Definition CPPScope.h:56
Cppyy::TCppType_t fCppType
Definition CPPScope.h:55
std::string remove_const(const std::string &cppname)
Definition TypeManip.cxx:80
std::string compound(const std::string &name)
PyObject * CreateScopeProxy(Cppyy::TCppScope_t, const unsigned flags=0)
bool CPPScope_Check(T *object)
Definition CPPScope.h:81
bool InsertDispatcher(CPPScope *klass, PyObject *bases, PyObject *dct, std::ostringstream &err)
size_t TCppIndex_t
Definition cpp_cppyy.h:24
RPY_EXPORTED TCppIndex_t GetNumTemplatedMethods(TCppScope_t scope, bool accept_namespace=false)
intptr_t TCppMethod_t
Definition cpp_cppyy.h:22
RPY_EXPORTED TCppIndex_t GetMethodReqArgs(TCppMethod_t)
RPY_EXPORTED std::vector< TCppIndex_t > GetMethodIndicesFromName(TCppScope_t scope, const std::string &name)
RPY_EXPORTED TCppIndex_t GetNumDatamembers(TCppScope_t scope, bool accept_namespace=false)
RPY_EXPORTED std::string GetMethodName(TCppMethod_t)
RPY_EXPORTED bool Compile(const std::string &code, bool silent=false)
RPY_EXPORTED bool IsProtectedData(TCppScope_t scope, TCppIndex_t idata)
RPY_EXPORTED bool IsConstructor(TCppMethod_t method)
RPY_EXPORTED TCppIndex_t GetNumMethods(TCppScope_t scope, bool accept_namespace=false)
TCppScope_t TCppType_t
Definition cpp_cppyy.h:19
RPY_EXPORTED TCppIndex_t GetMethodNumArgs(TCppMethod_t)
RPY_EXPORTED std::string GetBaseName(TCppType_t type, TCppIndex_t ibase)
RPY_EXPORTED bool IsNamespace(TCppScope_t scope)
RPY_EXPORTED std::string GetScopedFinalName(TCppType_t type)
RPY_EXPORTED std::string GetMethodArgType(TCppMethod_t, TCppIndex_t iarg)
RPY_EXPORTED TCppIndex_t GetDatamemberIndex(TCppScope_t scope, const std::string &name)
RPY_EXPORTED TCppMethod_t GetMethod(TCppScope_t scope, TCppIndex_t imeth)
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
RPY_EXPORTED bool HasVirtualDestructor(TCppType_t type)
RPY_EXPORTED bool IsConstMethod(TCppMethod_t)
size_t TCppScope_t
Definition cpp_cppyy.h:18
RPY_EXPORTED bool IsTemplatedConstructor(TCppScope_t scope, TCppIndex_t imeth)
RPY_EXPORTED TCppIndex_t GetNumBases(TCppType_t type)
RPY_EXPORTED std::string GetMethodResultType(TCppMethod_t)
RPY_EXPORTED std::string GetFinalName(TCppType_t type)
RPY_EXPORTED std::string GetDatamemberName(TCppScope_t scope, TCppIndex_t idata)
RPY_EXPORTED bool IsPublicMethod(TCppMethod_t method)
RPY_EXPORTED bool IsProtectedMethod(TCppMethod_t method)