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