Logo ROOT  
Reference Guide
ProxyWrappers.cxx
Go to the documentation of this file.
1 // Bindings
2 #include "CPyCppyy.h"
3 #include "ProxyWrappers.h"
4 #include "CPPClassMethod.h"
5 #include "CPPConstructor.h"
6 #include "CPPDataMember.h"
7 #include "CPPExcInstance.h"
8 #include "CPPFunction.h"
9 #include "CPPGetSetItem.h"
10 #include "CPPInstance.h"
11 #include "CPPMethod.h"
12 #include "CPPOverload.h"
13 #include "CPPScope.h"
14 #include "MemoryRegulator.h"
15 #include "PyStrings.h"
16 #include "Pythonize.h"
17 #include "TemplateProxy.h"
18 #include "TupleOfInstances.h"
19 #include "TypeManip.h"
20 #include "Utility.h"
21 
22 // Standard
23 #include <algorithm>
24 #include <deque>
25 #include <map>
26 #include <set>
27 #include <string>
28 #include <vector>
29 
30 
31 //- data _______________________________________________________________________
32 namespace CPyCppyy {
33  extern PyObject* gThisModule;
34  extern PyObject* gPyTypeMap;
35  extern std::set<Cppyy::TCppType_t> gPinnedTypes;
36 }
37 
38 // to prevent having to walk scopes, track python classes by C++ class
39 typedef std::map<Cppyy::TCppScope_t, PyObject*> PyClassMap_t;
41 
42 
43 //- helpers --------------------------------------------------------------------
44 
45 namespace CPyCppyy {
46 
47 typedef struct {
48  PyObject_HEAD
49  PyObject *dict;
50 } proxyobject;
51 
52 // helper for creating new C++ proxy python types
54 {
55 // Create a new python shadow class with the required hierarchy and meta-classes.
56  PyObject* pymetabases = PyTuple_New(PyTuple_GET_SIZE(pybases));
57  for (int i = 0; i < PyTuple_GET_SIZE(pybases); ++i) {
58  PyObject* btype = (PyObject*)Py_TYPE(PyTuple_GetItem(pybases, i));
59  Py_INCREF(btype);
60  PyTuple_SET_ITEM(pymetabases, i, btype);
61  }
62 
63  std::string name = Cppyy::GetFinalName(klass);
64 
65 // create meta-class, add a dummy __module__ to pre-empt the default setting
66  PyObject* args = Py_BuildValue((char*)"sO{}", (name+"_meta").c_str(), pymetabases);
67  PyDict_SetItem(PyTuple_GET_ITEM(args, 2), PyStrings::gModule, Py_True);
68  Py_DECREF(pymetabases);
69 
70  PyObject* pymeta = (PyObject*)CPPScopeMeta_New(klass, args);
71  Py_DECREF(args);
72  if (!pymeta) {
73  PyErr_Print();
74  return nullptr;
75  }
76 
77 // alright, and now we really badly want to get rid of the dummy ...
78  PyObject* dictproxy = PyObject_GetAttr(pymeta, PyStrings::gDict);
79  PyDict_DelItem(((proxyobject*)dictproxy)->dict, PyStrings::gModule);
80 
81 // create actual class
82  args = Py_BuildValue((char*)"sO{}", name.c_str(), pybases);
83  PyObject* pyclass =
84  ((PyTypeObject*)pymeta)->tp_new((PyTypeObject*)pymeta, args, nullptr);
85 
86  Py_DECREF(args);
87  Py_DECREF(pymeta);
88 
89  return pyclass;
90 }
91 
92 static inline
95 {
96  CPyCppyy::CPPDataMember* property = CPyCppyy::CPPDataMember_New(scope, idata);
97  PyObject* pname = CPyCppyy_PyText_InternFromString(const_cast<char*>(property->GetName().c_str()));
98 
99 // allow access at the instance level
100  PyType_Type.tp_setattro(pyclass, pname, (PyObject*)property);
101 
102 // allow access at the class level (always add after setting instance level)
103  if (Cppyy::IsStaticData(scope, idata))
104  PyType_Type.tp_setattro((PyObject*)Py_TYPE(pyclass), pname, (PyObject*)property);
105 
106 // cleanup
107  Py_DECREF(pname);
108  Py_DECREF(property);
109 }
110 
111 static inline
112 void AddScopeToParent(PyObject* parent, const std::string& name, PyObject* newscope)
113 {
115  if (CPPScope_Check(parent)) PyType_Type.tp_setattro(parent, pyname, newscope);
116  else PyObject_SetAttr(parent, pyname, newscope);
117  Py_DECREF(pyname);
118 }
119 
120 } // namespace CPyCppyy
121 
122 
123 //- public functions ---------------------------------------------------------
124 namespace CPyCppyy {
125 
126 static inline void sync_templates(
127  PyObject* pyclass, const std::string& mtCppName, const std::string& mtName)
128 {
129  PyObject* dct = PyObject_GetAttr(pyclass, PyStrings::gDict);
130  PyObject* pyname = CPyCppyy_PyText_InternFromString(const_cast<char*>(mtName.c_str()));
131  PyObject* attr = PyObject_GetItem(dct, pyname);
132  if (!attr) PyErr_Clear();
133  Py_DECREF(dct);
134  if (!TemplateProxy_Check(attr)) {
135  TemplateProxy* pytmpl = TemplateProxy_New(mtCppName, mtName, pyclass);
136  if (CPPOverload_Check(attr)) pytmpl->MergeOverload((CPPOverload*)attr);
137  PyType_Type.tp_setattro(pyclass, pyname, (PyObject*)pytmpl);
138  Py_DECREF(pytmpl);
139  }
140  Py_XDECREF(attr);
141  Py_DECREF(pyname);
142 }
143 
145 {
146 // Collect methods and data for the given scope, and add them to the given python
147 // proxy object.
148 
149 // some properties that'll affect building the dictionary
150  bool isNamespace = Cppyy::IsNamespace(scope);
151  bool isAbstract = Cppyy::IsAbstract(scope);
152  bool hasConstructor = false;
154 
155 // load all public methods and data members
156  typedef std::vector<PyCallable*> Callables_t;
157  typedef std::map<std::string, Callables_t> CallableCache_t;
158  CallableCache_t cache;
159 
160 // bypass custom __getattr__ for efficiency
161  getattrofunc oldgetattro = Py_TYPE(pyclass)->tp_getattro;
162  Py_TYPE(pyclass)->tp_getattro = PyType_Type.tp_getattro;
163 
164 // functions in namespaces are properly found through lazy lookup, so do not
165 // create them until needed (the same is not true for data members)
166  const Cppyy::TCppIndex_t nMethods = isNamespace ? 0 : Cppyy::GetNumMethods(scope);
167  for (Cppyy::TCppIndex_t imeth = 0; imeth < nMethods; ++imeth) {
168  Cppyy::TCppMethod_t method = Cppyy::GetMethod(scope, imeth);
169 
170  // process the method based on its name
171  std::string mtCppName = Cppyy::GetMethodName(method);
172 
173  // special case trackers
174  bool setupSetItem = false;
175  bool isConstructor = Cppyy::IsConstructor(method);
176  bool isTemplate = isConstructor ? false : Cppyy::IsMethodTemplate(scope, imeth);
177 
178  // filter empty names (happens for namespaces, is bug?)
179  if (mtCppName == "")
180  continue;
181 
182  // filter C++ destructors
183  if (mtCppName[0] == '~')
184  continue;
185 
186  // translate operators
187  std::string mtName = Utility::MapOperatorName(mtCppName, Cppyy::GetMethodNumArgs(method));
188  if (mtName.empty())
189  continue;
190 
191  // operator[]/() returning a reference type will be used for __setitem__
192  bool isCall = mtName == "__call__";
193  if (isCall || mtName == "__getitem__") {
194  const std::string& qual_return = Cppyy::ResolveName(Cppyy::GetMethodResultType(method));
195  const std::string& cpd = Utility::Compound(qual_return);
196  if (!cpd.empty() && cpd[cpd.size()- 1] == '&' && \
197  qual_return.find("const", 0, 5) == std::string::npos) {
198  if (isCall && !potGetItem) potGetItem = method;
199  setupSetItem = true; // will add methods as overloads
200  } else if (isCall && 1 < Cppyy::GetMethodNumArgs(method)) {
201  // not a non-const by-ref return, thus better __getitem__ candidate; the
202  // requirement for multiple arguments is that there is otherwise no benefit
203  // over the use of normal __getitem__ (this allows multi-indexing argumenst,
204  // which is clean in Python, but not allowed in C++)
205  potGetItem = method;
206  }
207  }
208 
209  // do not expose private methods as the Cling wrappers for them won't compile
210  if (!Cppyy::IsPublicMethod(method))
211  continue;
212 
213  // template members; handled by adding a dispatcher to the class
214  bool storeOnTemplate =
215  isTemplate ? true : (!isConstructor && Cppyy::ExistsMethodTemplate(scope, mtCppName));
216  if (storeOnTemplate) {
217  sync_templates(pyclass, mtCppName, mtName);
218  // continue processing to actually add the method so that the proxy can find
219  // it on the class when called explicitly
220  }
221 
222  // construct the holder
223  PyCallable* pycall = nullptr;
224  if (Cppyy::IsStaticMethod(method)) // class method
225  pycall = new CPPClassMethod(scope, method);
226  else if (isNamespace) // free function
227  pycall = new CPPFunction(scope, method);
228  else if (isConstructor) { // ctor
229  mtName = "__init__";
230  hasConstructor = true;
231  if (!isAbstract)
232  pycall = new CPPConstructor(scope, method);
233  else
234  pycall = new CPPAbstractClassConstructor(scope, method);
235  } else // member function
236  pycall = new CPPMethod(scope, method);
237 
238  if (storeOnTemplate) {
239  // template proxy was already created in sync_templates call above, so
240  // add only here, not to the cache of collected methods
241  PyObject* attr = PyObject_GetAttrString(pyclass, const_cast<char*>(mtName.c_str()));
242  if (isTemplate) ((TemplateProxy*)attr)->AdoptTemplate(pycall);
243  else ((TemplateProxy*)attr)->AdoptMethod(pycall);
244  Py_DECREF(attr);
245 
246  // for operator[]/() that returns by ref, also add __setitem__
247  if (setupSetItem) {
248  TemplateProxy* pysi = (TemplateProxy*)PyObject_GetAttrString(pyclass, const_cast<char*>("__setitem__"));
249  if (!pysi) {
250  pysi = TemplateProxy_New(mtCppName, "__setitem__", pyclass);
251  PyObject_SetAttrString(pyclass, const_cast<char*>("__setitem__"), (PyObject*)pysi);
252  }
253  if (isTemplate) pysi->AdoptTemplate(new CPPSetItem(scope, method));
254  else pysi->AdoptMethod(new CPPSetItem(scope, method));
255  Py_XDECREF(pysi);
256  }
257 
258  } else {
259  // lookup method dispatcher and store method
260  Callables_t& md = (*(cache.insert(
261  std::make_pair(mtName, Callables_t())).first)).second;
262  md.push_back(pycall);
263 
264  // special case for operator[]/() that returns by ref, use for getitem/call and setitem
265  if (setupSetItem) {
266  Callables_t& setitem = (*(cache.insert(
267  std::make_pair(std::string("__setitem__"), Callables_t())).first)).second;
268  setitem.push_back(new CPPSetItem(scope, method));
269  }
270  }
271  }
272 
273 // add proxies for un-instantiated/non-overloaded templated methods
274  const Cppyy::TCppIndex_t nTemplMethods = isNamespace ? 0 : Cppyy::GetNumTemplatedMethods(scope);
275  for (Cppyy::TCppIndex_t imeth = 0; imeth < nTemplMethods; ++imeth) {
276  const std::string mtCppName = Cppyy::GetTemplatedMethodName(scope, imeth);
277  // the number of arguments isn't known until instantiation and as far as C++ is concerned, all
278  // same-named operators are simply overloads; so will pre-emptively add both names if with and
279  // without arguments differ, letting the normal overload mechanism resolve on call
280  bool isConstructor = Cppyy::IsTemplatedConstructor(scope, imeth);
281 
282  // first add with no arguments
283  std::string mtName0 = isConstructor ? "__init__" : Utility::MapOperatorName(mtCppName, false);
284  sync_templates(pyclass, mtCppName, mtName0);
285 
286  // then add when taking arguments, if this method is different
287  if (!isConstructor) {
288  std::string mtName1 = Utility::MapOperatorName(mtCppName, true);
289  if (mtName0 != mtName1)
290  sync_templates(pyclass, mtCppName, mtName1);
291  }
292  }
293 
294 // add a pseudo-default ctor, if none defined
295  if (!hasConstructor) {
296  PyCallable* defctor = nullptr;
297  if (isAbstract)
298  defctor = new CPPAbstractClassConstructor(scope, (Cppyy::TCppMethod_t)0);
299  else if (isNamespace)
300  defctor = new CPPNamespaceConstructor(scope, (Cppyy::TCppMethod_t)0);
301  else if (!Cppyy::IsComplete(Cppyy::GetScopedFinalName(scope))) {
302  ((CPPScope*)pyclass)->fFlags |= CPPScope::kIsInComplete;
303  defctor = new CPPIncompleteClassConstructor(scope, (Cppyy::TCppMethod_t)0);
304  } else
305  defctor = new CPPConstructor(scope, (Cppyy::TCppMethod_t)0);
306  cache["__init__"].push_back(defctor);
307  }
308 
309 // map __call__ to __getitem__ if also mapped to __setitem__
310  if (potGetItem) {
311  Callables_t& getitem = (*(cache.insert(
312  std::make_pair(std::string("__getitem__"), Callables_t())).first)).second;
313  getitem.push_back(new CPPGetItem(scope, potGetItem));
314  }
315 
316 // add the methods to the class dictionary
317  PyObject* dct = PyObject_GetAttr(pyclass, PyStrings::gDict);
318  for (CallableCache_t::iterator imd = cache.begin(); imd != cache.end(); ++imd) {
319  // in order to prevent removing templated editions of this method (which were set earlier,
320  // above, as a different proxy object), we'll check and add this method flagged as a generic
321  // one (to be picked up by the templated one as appropriate) if a template exists
322  PyObject* pyname = CPyCppyy_PyText_FromString(const_cast<char*>(imd->first.c_str()));
323  PyObject* attr = PyObject_GetItem(dct, pyname);
324  Py_DECREF(pyname);
325  if (TemplateProxy_Check(attr)) {
326  // template exists, supply it with the non-templated method overloads
327  for (auto cit : imd->second)
328  ((TemplateProxy*)attr)->AdoptMethod(cit);
329  } else {
330  if (!attr) PyErr_Clear();
331  // normal case, add a new method
332  CPPOverload* method = CPPOverload_New(imd->first, imd->second);
333  PyObject* pymname = CPyCppyy_PyText_InternFromString(const_cast<char*>(method->GetName().c_str()));
334  PyType_Type.tp_setattro(pyclass, pymname, (PyObject*)method);
335  Py_DECREF(pymname);
336  Py_DECREF(method);
337  }
338 
339  Py_XDECREF(attr); // could have been found in base class or non-existent
340  }
341  Py_DECREF(dct);
342 
343  // collect data members (including enums)
344  const Cppyy::TCppIndex_t nDataMembers = Cppyy::GetNumDatamembers(scope);
345  for (Cppyy::TCppIndex_t idata = 0; idata < nDataMembers; ++idata) {
346  // allow only public members
347  if (!Cppyy::IsPublicData(scope, idata))
348  continue;
349 
350  // enum datamembers (this in conjunction with previously collected enums above)
351  if (Cppyy::IsEnumData(scope, idata) && Cppyy::IsStaticData(scope, idata)) {
352  // some implementation-specific data members have no address: ignore them
353  if (!Cppyy::GetDatamemberOffset(scope, idata))
354  continue;
355 
356  // two options: this is a static variable, or it is the enum value, the latter
357  // already exists, so check for it and move on if set
358  PyObject* eset = PyObject_GetAttrString(pyclass,
359  const_cast<char*>(Cppyy::GetDatamemberName(scope, idata).c_str()));
360  if (eset) {
361  Py_DECREF(eset);
362  continue;
363  }
364 
365  PyErr_Clear();
366 
367  // it could still be that this is an anonymous enum, which is not in the list
368  // provided by the class
369  if (strstr(Cppyy::GetDatamemberType(scope, idata).c_str(), "(anonymous)") != 0) {
370  AddPropertyToClass(pyclass, scope, idata);
371  continue;
372  }
373  }
374 
375  // properties (aka public (static) data members)
376  AddPropertyToClass(pyclass, scope, idata);
377  }
378 
379 // restore custom __getattr__
380  Py_TYPE(pyclass)->tp_getattro = oldgetattro;
381 
382 // all ok, done
383  return 0;
384 }
385 
386 //----------------------------------------------------------------------------
387 static void CollectUniqueBases(Cppyy::TCppType_t klass, std::deque<std::string>& uqb)
388 {
389 // collect bases in acceptable mro order, while removing duplicates (this may
390 // break the overload resolution in esoteric cases, but otherwise the class can
391 // not be used at all, as CPython will refuse the mro).
392  size_t nbases = Cppyy::GetNumBases(klass);
393 
394  std::deque<Cppyy::TCppType_t> bids;
395  for (size_t ibase = 0; ibase < nbases; ++ibase) {
396  const std::string& name = Cppyy::GetBaseName(klass, ibase);
397  int decision = 2;
399  if (!tp) continue; // means this base with not be available Python-side
400  for (size_t ibase2 = 0; ibase2 < uqb.size(); ++ibase2) {
401  if (uqb[ibase2] == name) { // not unique ... skip
402  decision = 0;
403  break;
404  }
405 
406  if (Cppyy::IsSubtype(tp, bids[ibase2])) {
407  // mro requirement: sub-type has to follow base
408  decision = 1;
409  break;
410  }
411  }
412 
413  if (decision == 1) {
414  uqb.push_front(name);
415  bids.push_front(tp);
416  } else if (decision == 2) {
417  uqb.push_back(name);
418  bids.push_back(tp);
419  }
420  // skipped if decision == 0 (not unique)
421  }
422 }
423 
425 {
426 // Build a tuple of python proxy classes of all the bases of the given 'klass'.
427  std::deque<std::string> uqb;
428  CollectUniqueBases(klass, uqb);
429 
430 // allocate a tuple for the base classes, special case for first base
431  size_t nbases = uqb.size();
432 
433  PyObject* pybases = PyTuple_New(nbases ? nbases : 1);
434  if (!pybases)
435  return nullptr;
436 
437 // build all the bases
438  if (nbases == 0) {
439  Py_INCREF((PyObject*)(void*)&CPPInstance_Type);
440  PyTuple_SET_ITEM(pybases, 0, (PyObject*)(void*)&CPPInstance_Type);
441  } else {
442  for (std::deque<std::string>::size_type ibase = 0; ibase < nbases; ++ibase) {
443  PyObject* pyclass = CreateScopeProxy(uqb[ibase]);
444  if (!pyclass) {
445  Py_DECREF(pybases);
446  return nullptr;
447  }
448 
449  PyTuple_SET_ITEM(pybases, ibase, pyclass);
450  }
451 
452  // special case, if true python types enter the hierarchy, make sure that
453  // the first base seen is still the CPPInstance_Type
454  if (!PyObject_IsSubclass(PyTuple_GET_ITEM(pybases, 0), (PyObject*)&CPPInstance_Type)) {
455  PyObject* newpybases = PyTuple_New(nbases+1);
456  Py_INCREF((PyObject*)(void*)&CPPInstance_Type);
457  PyTuple_SET_ITEM(newpybases, 0, (PyObject*)(void*)&CPPInstance_Type);
458  for (int ibase = 0; ibase < (int)nbases; ++ibase) {
459  PyObject* pyclass = PyTuple_GET_ITEM(pybases, ibase);
460  Py_INCREF(pyclass);
461  PyTuple_SET_ITEM(newpybases, ibase+1, pyclass);
462  }
463  Py_DECREF(pybases);
464  pybases = newpybases;
465  }
466  }
467 
468  return pybases;
469 }
470 
471 } // namespace CPyCppyy
472 
473 //----------------------------------------------------------------------------
475 {
476 // Retrieve scope proxy from the known ones.
477  PyClassMap_t::iterator pci = gPyClasses.find(scope);
478  if (pci != gPyClasses.end()) {
479  PyObject* pyclass = PyWeakref_GetObject(pci->second);
480  if (pyclass != Py_None) {
481  Py_INCREF(pyclass);
482  return pyclass;
483  }
484  }
485 
486  return nullptr;
487 }
488 
489 //----------------------------------------------------------------------------
491 {
492 // Convenience function with a lookup first through the known existing proxies.
493  PyObject* pyclass = GetScopeProxy(scope);
494  if (pyclass)
495  return pyclass;
496 
498 }
499 
500 //----------------------------------------------------------------------------
502 {
503 // Build a python shadow class for the named C++ class.
504  std::string cname = CPyCppyy_PyText_AsString(PyTuple_GetItem(args, 0));
505  if (PyErr_Occurred())
506  return nullptr;
507 
508  return CreateScopeProxy(cname);
509 }
510 
511 //----------------------------------------------------------------------------
512 PyObject* CPyCppyy::CreateScopeProxy(const std::string& name, PyObject* parent)
513 {
514 // Build a python shadow class for the named C++ class or namespace.
515 
516 // determine complete scope name, if a python parent has been given
517  std::string scName = "";
518  if (parent) {
519  if (CPPScope_Check(parent))
520  scName = Cppyy::GetScopedFinalName(((CPPScope*)parent)->fCppType);
521  else {
522  PyObject* parname = PyObject_GetAttr(parent, PyStrings::gName);
523  if (!parname) {
524  PyErr_Format(PyExc_SystemError, "given scope has no name for %s", name.c_str());
525  return nullptr;
526  }
527 
528  // should be a string
529  scName = CPyCppyy_PyText_AsString(parname);
530  Py_DECREF(parname);
531  if (PyErr_Occurred())
532  return nullptr;
533  }
534 
535  // accept this parent scope and use it's name for prefixing
536  Py_INCREF(parent);
537  }
538 
539 // retrieve C++ class (this verifies name, and is therefore done first)
540  const std::string& lookup = scName.empty() ? name : (scName+"::"+name);
541  Cppyy::TCppScope_t klass = Cppyy::GetScope(lookup);
542 
543  if (!(bool)klass && Cppyy::IsTemplate(lookup)) {
544  // a "naked" templated class is requested: return callable proxy for instantiations
545  PyObject* pytcl = PyObject_GetAttr(gThisModule, PyStrings::gTemplate);
546  PyObject* pytemplate = PyObject_CallFunction(
547  pytcl, const_cast<char*>("s"), const_cast<char*>(lookup.c_str()));
548  Py_DECREF(pytcl);
549 
550  // cache the result
551  AddScopeToParent(parent ? parent : gThisModule, name, pytemplate);
552 
553  // done, next step should be a call into this template
554  Py_XDECREF(parent);
555  return pytemplate;
556  }
557 
558  if (!(bool)klass) {
559  // could be an enum, which are treated seperately in CPPScope (TODO: maybe they
560  // should be handled here instead anyway??)
561  if (Cppyy::IsEnum(lookup))
562  return nullptr;
563 
564  // final possibility is a typedef of a builtin; these are mapped on the python side
565  std::string resolved = Cppyy::ResolveName(lookup);
566  if (gPyTypeMap) {
567  PyObject* tc = PyDict_GetItemString(gPyTypeMap, resolved.c_str()); // borrowed
568  if (tc && PyCallable_Check(tc)) {
569  PyObject* nt = PyObject_CallFunction(tc, (char*)"ss", name.c_str(), scName.c_str());
570  if (nt) {
571  if (parent) {
572  AddScopeToParent(parent, name, nt);
573  Py_DECREF(parent);
574  }
575  return nt;
576  }
577  PyErr_Clear();
578  }
579  }
580 
581  // all options have been exhausted: it doesn't exist as such
582  PyErr_Format(PyExc_TypeError, "\'%s\' is not a known C++ class", lookup.c_str());
583  Py_XDECREF(parent);
584  return nullptr;
585  }
586 
587 // locate class by ID, if possible, to prevent parsing scopes/templates anew
588  PyObject* pyscope = GetScopeProxy(klass);
589  if (pyscope) {
590  if (parent) {
591  AddScopeToParent(parent, name, pyscope);
592  Py_DECREF(parent);
593  }
594  return pyscope;
595  }
596 
597 // now have a class ... get the actual, fully scoped class name, so that typedef'ed
598 // classes are created in the right place
599  const std::string& actual = Cppyy::GetScopedFinalName(klass);
600  if (actual != lookup) {
601  pyscope = CreateScopeProxy(actual);
602  if (!pyscope) PyErr_Clear();
603  }
604 
605 // locate the parent, if necessary, for memoizing the class if not specified
606  std::string::size_type last = 0;
607  if (!parent) {
608  // TODO: move this to TypeManip, which already has something similar in
609  // the form of 'extract_namespace'
610  // need to deal with template parameters that can have scopes themselves
611  int tpl_open = 0;
612  for (std::string::size_type pos = 0; pos < name.size(); ++pos) {
613  std::string::value_type c = name[pos];
614 
615  // count '<' and '>' to be able to skip template contents
616  if (c == '<')
617  ++tpl_open;
618  else if (c == '>')
619  --tpl_open;
620 
621  // by only checking for "::" the last part (class name) is dropped
622  else if (tpl_open == 0 && \
623  c == ':' && pos+1 < name.size() && name[ pos+1 ] == ':') {
624  // found a new scope part
625  const std::string& part = name.substr(last, pos-last);
626 
627  PyObject* next = PyObject_GetAttrString(
628  parent ? parent : gThisModule, const_cast<char*>(part.c_str()));
629 
630  if (!next) { // lookup failed, try to create it
631  PyErr_Clear();
632  next = CreateScopeProxy(part, parent);
633  }
634  Py_XDECREF(parent);
635 
636  if (!next) // create failed, give up
637  return nullptr;
638 
639  // found scope part
640  parent = next;
641 
642  // done with part (note that pos is moved one ahead here)
643  last = pos+2; ++pos;
644  }
645  }
646 
647  if (parent && !CPPScope_Check(parent)) {
648  // Special case: parent found is not one of ours (it's e.g. a pure Python module), so
649  // continuing would fail badly. One final lookup, then out of here ...
650  std::string unscoped = name.substr(last, std::string::npos);
651  PyObject* ret = PyObject_GetAttrString(parent, unscoped.c_str());
652  Py_DECREF(parent);
653  return ret;
654  }
655  }
656 
657 // use the module as a fake scope if no outer scope found
658  if (!parent) {
659  Py_INCREF(gThisModule);
660  parent = gThisModule;
661  }
662 
663 // if the scope was earlier found as actual, then we're done already, otherwise
664 // build a new scope proxy
665  if (!pyscope) {
666  // construct the base classes
667  PyObject* pybases = BuildCppClassBases(klass);
668  if (pybases != 0) {
669  // create a fresh Python class, given bases, name, and empty dictionary
670  pyscope = CreateNewCppProxyClass(klass, pybases);
671  Py_DECREF(pybases);
672  }
673 
674  // fill the dictionary, if successful
675  if (pyscope) {
676  if (BuildScopeProxyDict(klass, pyscope)) {
677  // something failed in building the dictionary
678  Py_DECREF(pyscope);
679  pyscope = nullptr;
680  }
681  }
682 
683  // store a ref from cppyy scope id to new python class
684  if (pyscope && !(((CPPScope*)pyscope)->fFlags & CPPScope::kIsInComplete)) {
685  gPyClasses[klass] = PyWeakref_NewRef(pyscope, nullptr);
686 
687  if (!(((CPPScope*)pyscope)->fFlags & CPPScope::kIsNamespace)) {
688  // add python-style features to classes only
689  if (!Pythonize(pyscope, Cppyy::GetScopedFinalName(klass))) {
690  Py_DECREF(pyscope);
691  pyscope = nullptr;
692  }
693  } else {
694  // add to sys.modules to allow importing from this namespace
695  PyObject* pyfullname = PyObject_GetAttr(pyscope, PyStrings::gModule);
697  CPyCppyy_PyText_AppendAndDel(&pyfullname, PyObject_GetAttr(pyscope, PyStrings::gName));
698  PyObject* modules = PySys_GetObject(const_cast<char*>("modules"));
699  if (modules && PyDict_Check(modules))
700  PyDict_SetItem(modules, pyfullname, pyscope);
701  Py_DECREF(pyfullname);
702  }
703  }
704  }
705 
706 // store on parent if found/created and complete
707  if (pyscope && !(((CPPScope*)pyscope)->fFlags & CPPScope::kIsInComplete))
708  AddScopeToParent(parent, name, pyscope);
709  Py_DECREF(parent);
710 
711 // all done
712  return pyscope;
713 }
714 
715 
716 //----------------------------------------------------------------------------
718 {
719 // To allow use of C++ exceptions in lieue of Python exceptions, they need to
720 // derive from BaseException, which can not mix with the normal CPPInstance and
721 // use of the meta-class. Instead, encapsulate them in a forwarding class that
722 // derives from Pythons Exception class
723 
724 // start with creation of CPPExcInstance type base classes
725  std::deque<std::string> uqb;
726  CollectUniqueBases(((CPPScope*)pyscope)->fCppType, uqb);
727  size_t nbases = uqb.size();
728 
729 // Support for multiple bases actually can not actually work as-is: the reason
730 // for deriving from BaseException is to guarantee the layout needed for storing
731 // traces. If some other base is std::exception (as e.g. boost::bad_any_cast) or
732 // also derives from std::exception, then there are two trace locations. OTOH,
733 // if the other class is a non-exception type, then the exception class does not
734 // need to derive from it because it can never be caught as that type forwarding
735 // to the proxy will work as expected, through, which is good enough).
736 //
737 // The code below restricts the hierarchy to a single base class, picking the
738 // "best" by filtering std::exception and non-exception bases.
739 
740  PyObject* pybases = PyTuple_New(1);
741  if (nbases == 0) {
742  Py_INCREF((PyObject*)(void*)&CPPExcInstance_Type);
743  PyTuple_SET_ITEM(pybases, 0, (PyObject*)(void*)&CPPExcInstance_Type);
744  } else {
745  PyObject* best_base = nullptr;
746 
747  for (std::deque<std::string>::size_type ibase = 0; ibase < nbases; ++ibase) {
748  // retrieve bases through their enclosing scope to guarantee treatment as
749  // exception classes and proper caching
750  const std::string& finalname = Cppyy::GetScopedFinalName(Cppyy::GetScope(uqb[ibase]));
751  const std::string& parentname = TypeManip::extract_namespace(finalname);
752  PyObject* base_parent = CreateScopeProxy(parentname);
753  if (!base_parent) {
754  Py_DECREF(pybases);
755  return nullptr;
756  }
757 
758  PyObject* excbase = PyObject_GetAttrString(base_parent,
759  parentname.empty() ? finalname.c_str() : finalname.substr(parentname.size()+2, std::string::npos).c_str());
760  Py_DECREF(base_parent);
761  if (!excbase) {
762  Py_DECREF(pybases);
763  return nullptr;
764  }
765 
766  if (PyType_IsSubtype((PyTypeObject*)excbase, &CPPExcInstance_Type)) {
767  Py_XDECREF(best_base);
768  best_base = excbase;
769  if (finalname != "std::exception")
770  break;
771  } else {
772  // just skip: there will be at least one exception derived base class
773  Py_DECREF(excbase);
774  }
775  }
776 
777  PyTuple_SET_ITEM(pybases, 0, best_base);
778  }
779 
780  PyObject* args = Py_BuildValue((char*)"OO{}", pyname, pybases);
781 
782 // meta-class attributes (__cpp_name__, etc.) can not be resolved lazily so add
783 // them directly instead in case they are needed
784  PyObject* dct = PyTuple_GET_ITEM(args, 2);
785  PyDict_SetItem(dct, PyStrings::gUnderlying, pyscope);
786  PyDict_SetItem(dct, PyStrings::gName, PyObject_GetAttr(pyscope, PyStrings::gName));
787  PyDict_SetItem(dct, PyStrings::gCppName, PyObject_GetAttr(pyscope, PyStrings::gCppName));
788  PyDict_SetItem(dct, PyStrings::gModule, PyObject_GetAttr(pyscope, PyStrings::gModule));
789 
790 // create the actual exception class
791  PyObject* exc_pyscope = PyType_Type.tp_new(&PyType_Type, args, nullptr);
792  Py_DECREF(args);
793  Py_DECREF(pybases);
794 
795 // cache the result for future lookups and return
796  PyType_Type.tp_setattro(parent, pyname, exc_pyscope);
797  return exc_pyscope;
798 }
799 
800 
801 //----------------------------------------------------------------------------
803  Cppyy::TCppType_t klass, const unsigned flags)
804 {
805 // only known or knowable objects will be bound (null object is ok)
806  if (!klass) {
807  PyErr_SetString(PyExc_TypeError, "attempt to bind C++ object w/o class");
808  return nullptr;
809  }
810 
811 // retrieve python class
812  PyObject* pyclass = CreateScopeProxy(klass);
813  if (!pyclass)
814  return nullptr; // error has been set in CreateScopeProxy
815 
816  bool isRef = flags & CPPInstance::kIsReference;
817  bool isValue = flags & CPPInstance::kIsValue;
818 
819 // TODO: make sure that a consistent address is used (may have to be done in BindCppObject)
820  if (address && !isValue /* always fresh */ && !(flags & (CPPInstance::kNoWrapConv|CPPInstance::kNoMemReg))) {
821  PyObject* oldPyObject = MemoryRegulator::RetrievePyObject(
822  isRef ? *(void**)address : address, pyclass);
823 
824  // ptr-ptr requires old object to be a reference to enable re-use
825  if (oldPyObject && (!(flags & CPPInstance::kIsPtrPtr) ||
826  ((CPPInstance*)oldPyObject)->fFlags & CPPInstance::kIsReference)) {
827  return oldPyObject;
828  }
829  }
830 
831 // if smart, instantiate a Python-side object of the underlying type, carrying the smartptr
832  PyObject* smart_type = (flags != CPPInstance::kNoWrapConv && (((CPPClass*)pyclass)->fFlags & CPPScope::kIsSmart)) ? pyclass : nullptr;
833  if (smart_type) {
834  pyclass = CreateScopeProxy(((CPPSmartClass*)smart_type)->fUnderlyingType);
835  if (!pyclass) {
836  // simply restore and expose as the actual smart pointer class
837  pyclass = smart_type;
838  smart_type = nullptr;
839  }
840  }
841 
842 // instantiate an object of this class
843  PyObject* args = PyTuple_New(0);
844  CPPInstance* pyobj =
845  (CPPInstance*)((PyTypeObject*)pyclass)->tp_new((PyTypeObject*)pyclass, args, nullptr);
846  Py_DECREF(args);
847 
848 // bind, register and return if successful
849  if (pyobj != 0) { // fill proxy value?
850  unsigned objflags =
851  (isRef ? CPPInstance::kIsReference : 0) | (isValue ? CPPInstance::kIsValue : 0) | (flags & CPPInstance::kIsOwner);
852  pyobj->Set(address, (CPPInstance::EFlags)objflags);
853 
854  if (smart_type)
855  pyobj->SetSmart(smart_type);
856 
857  // do not register null pointers, references (?), or direct usage of smart pointers or iterators
858  if (address && !isRef && !(flags & (CPPInstance::kNoWrapConv|CPPInstance::kNoMemReg)))
859  MemoryRegulator::RegisterPyObject(pyobj, pyobj->GetObject());
860  }
861 
862 // successful completion; wrap exception options to make them raiseable, normal return otherwise
863  if (((CPPClass*)pyclass)->fFlags & CPPScope::kIsException) {
864  PyObject* exc_obj = CPPExcInstance_Type.tp_new(&CPPExcInstance_Type, nullptr, nullptr);
865  ((CPPExcInstance*)exc_obj)->fCppInstance = (PyObject*)pyobj;
866  Py_DECREF(pyclass);
867  return exc_obj;
868  }
869 
870  Py_DECREF(pyclass);
871 
872  return (PyObject*)pyobj;
873 }
874 
875 //----------------------------------------------------------------------------
877  Cppyy::TCppType_t klass, const unsigned flags)
878 {
879 // if the object is a null pointer, return a typed one (as needed for overloading)
880  if (!address)
881  return BindCppObjectNoCast(address, klass, flags);
882 
883 // only known or knowable objects will be bound
884  if (!klass) {
885  PyErr_SetString(PyExc_TypeError, "attempt to bind C++ object w/o class");
886  return nullptr;
887  }
888 
889  bool isRef = flags & CPPInstance::kIsReference;
890 
891 // get actual class for recycling checking and/or downcasting
892  Cppyy::TCppType_t clActual = isRef ? 0 : Cppyy::GetActualClass(klass, address);
893 
894 // downcast to real class for object returns, unless pinned
895  if (clActual && klass != clActual) {
896  auto pci = gPinnedTypes.find(klass);
897  if (pci == gPinnedTypes.end()) {
898  intptr_t offset = Cppyy::GetBaseOffset(
899  clActual, klass, address, -1 /* down-cast */, true /* report errors */);
900  if (offset != -1) { // may fail if clActual not fully defined
901  address = (void*)((intptr_t)address + offset);
902  klass = clActual;
903  }
904  }
905  }
906 
907 // actual binding (returned object may be zero w/ a python exception set)
908  return BindCppObjectNoCast(address, klass, flags);
909 }
910 
911 //----------------------------------------------------------------------------
913  Cppyy::TCppObject_t address, Cppyy::TCppType_t klass, dims_t dims)
914 {
915 // TODO: this function exists for symmetry; need to figure out if it's useful
916  return TupleOfInstances_New(address, klass, dims[0], dims+1);
917 }
CPyCppyy
Set of helper functions that are invoked from the pythonizors, on the Python side.
Definition: TPyClassGenerator.cxx:31
c
#define c(i)
Definition: RSha256.hxx:101
CPyCppyy::CPPScopeMeta_New
CPPScope * CPPScopeMeta_New(Cppyy::TCppScope_t klass, PyObject *args)
Definition: CPPScope.h:88
CPyCppyy::CPPExcInstance_Type
PyTypeObject CPPExcInstance_Type
Definition: CPPExcInstance.cxx:226
Cppyy::GetNumTemplatedMethods
RPY_EXPORTED TCppIndex_t GetNumTemplatedMethods(TCppScope_t scope)
Definition: clingwrapper.cxx:1558
kIsReference
@ kIsReference
Definition: TDictionary.h:82
CPyCppyy::PyStrings::gTemplate
PyObject * gTemplate
Definition: PyStrings.cxx:47
PyClassMap_t
std::map< Cppyy::TCppScope_t, PyObject * > PyClassMap_t
Definition: ProxyWrappers.cxx:39
CPPInstance.h
CPyCppyy::GetScopeProxy
PyObject * GetScopeProxy(Cppyy::TCppScope_t)
Definition: ProxyWrappers.cxx:474
CPyCppyy::PyStrings::gDict
PyObject * gDict
Definition: PyStrings.cxx:14
Cppyy::IsStaticData
RPY_EXPORTED bool IsStaticData(TCppScope_t scope, TCppIndex_t idata)
Definition: clingwrapper.cxx:2006
CPyCppyy::CPPDataMember
Definition: CPPDataMember.h:15
CPyCppyy::PyStrings::gModule
R__EXTERN PyObject * gModule
Definition: TPython.cxx:104
CPyCppyy::TypeManip::extract_namespace
std::string extract_namespace(const std::string &name)
Definition: TypeManip.cxx:159
Cppyy::IsEnumData
RPY_EXPORTED bool IsEnumData(TCppScope_t scope, TCppIndex_t idata)
Definition: clingwrapper.cxx:2031
PyObject
_object PyObject
Definition: PyMethodBase.h:42
Cppyy::GetDatamemberType
RPY_EXPORTED std::string GetDatamemberType(TCppScope_t scope, TCppIndex_t idata)
Definition: clingwrapper.cxx:1852
CPyCppyy::CPPInstance::Set
void Set(void *address, EFlags flags=kDefault)
Definition: CPPInstance.h:85
CPyCppyy::CPPDataMember_New
CPPDataMember * CPPDataMember_New(Cppyy::TCppScope_t scope, Cppyy::TCppIndex_t idata)
Definition: CPPDataMember.h:52
TupleOfInstances.h
CPyCppyy::CPPNamespaceConstructor
Definition: CPPConstructor.h:36
CPyCppyy::BuildScopeProxyDict
static int BuildScopeProxyDict(Cppyy::TCppScope_t scope, PyObject *pyclass)
Definition: ProxyWrappers.cxx:144
Utility.h
kIsNamespace
@ kIsNamespace
Definition: TDictionary.h:95
Cppyy::TCppScope_t
size_t TCppScope_t
Definition: cpp_cppyy.h:18
pyname
#define pyname
Definition: TMCParticle.cxx:19
CPPDataMember.h
Cppyy::IsStaticMethod
RPY_EXPORTED bool IsStaticMethod(TCppMethod_t method)
Definition: clingwrapper.cxx:1801
TemplateProxy.h
Cppyy::IsSubtype
RPY_EXPORTED bool IsSubtype(TCppType_t derived, TCppType_t base)
Definition: clingwrapper.cxx:1227
CPyCppyy::CPPInstance
Definition: CPPInstance.h:26
CPyCppyy::PyCallable
Definition: PyCallable.h:12
Cppyy::ResolveName
RPY_EXPORTED std::string ResolveName(const std::string &cppitem_name)
Definition: clingwrapper.cxx:381
Cppyy::GetTemplatedMethodName
RPY_EXPORTED std::string GetTemplatedMethodName(TCppScope_t scope, TCppIndex_t imeth)
Definition: clingwrapper.cxx:1575
CPyCppyy::BuildCppClassBases
static PyObject * BuildCppClassBases(Cppyy::TCppType_t klass)
Definition: ProxyWrappers.cxx:424
CPyCppyy::CPPSetItem
Definition: CPPGetSetItem.h:10
CPyCppyy::CreateExcScopeProxy
PyObject * CreateExcScopeProxy(PyObject *pyscope, PyObject *pyname, PyObject *parent)
Definition: ProxyWrappers.cxx:717
CPyCppyy::PyStrings::gUnderlying
PyObject * gUnderlying
Definition: PyStrings.cxx:31
CPyCppyy::TupleOfInstances_New
PyObject * TupleOfInstances_New(Cppyy::TCppObject_t address, Cppyy::TCppType_t klass, dim_t ndims, dims_t dims)
Definition: TupleOfInstances.cxx:89
CPyCppyy::AddScopeToParent
static void AddScopeToParent(PyObject *parent, const std::string &name, PyObject *newscope)
Definition: ProxyWrappers.cxx:112
Pythonize.h
CPyCppyy::AddPropertyToClass
static void AddPropertyToClass(PyObject *pyclass, Cppyy::TCppScope_t scope, Cppyy::TCppIndex_t idata)
Definition: ProxyWrappers.cxx:93
CPyCppyy::CPPOverload_New
CPPOverload * CPPOverload_New(const std::string &name, std::vector< PyCallable * > &methods)
Definition: CPPOverload.h:91
CPyCppyy::CPPInstance::GetObject
void * GetObject()
Definition: CPPInstance.h:93
CPyCppyy::CPPExcInstance
Definition: CPPExcInstance.h:14
CPyCppyy_PyText_FromString
#define CPyCppyy_PyText_FromString
Definition: CPyCppyy.h:102
Cppyy::GetMethodNumArgs
RPY_EXPORTED TCppIndex_t GetMethodNumArgs(TCppMethod_t)
Definition: clingwrapper.cxx:1461
CPyCppyy::CollectUniqueBases
static void CollectUniqueBases(Cppyy::TCppType_t klass, std::deque< std::string > &uqb)
Definition: ProxyWrappers.cxx:387
MemoryRegulator.h
CPyCppyy_PyText_AppendAndDel
#define CPyCppyy_PyText_AppendAndDel
Definition: CPyCppyy.h:105
gPyClasses
static PyClassMap_t gPyClasses
Definition: ProxyWrappers.cxx:40
CPyCppyy::CPPOverload::GetName
const std::string & GetName() const
Definition: CPPOverload.h:62
CPyCppyy_PyText_InternFromString
#define CPyCppyy_PyText_InternFromString
Definition: CPyCppyy.h:103
CPPExcInstance.h
CPyCppyy::Utility::MapOperatorName
std::string MapOperatorName(const std::string &name, bool bTakesParames)
Definition: Utility.cxx:727
Cppyy::GetActualClass
RPY_EXPORTED TCppType_t GetActualClass(TCppType_t klass, TCppObject_t obj)
Definition: clingwrapper.cxx:565
CPyCppyy::TemplateProxy::MergeOverload
void MergeOverload(CPPOverload *mp)
Definition: TemplateProxy.cxx:94
CPPClassMethod.h
Cppyy::IsConstructor
RPY_EXPORTED bool IsConstructor(TCppMethod_t method)
Definition: clingwrapper.cxx:1783
Cppyy::GetBaseName
RPY_EXPORTED std::string GetBaseName(TCppType_t type, TCppIndex_t ibase)
Definition: clingwrapper.cxx:1221
CPyCppyy::CPPOverload_Check
bool CPPOverload_Check(T *object)
Definition: CPPOverload.h:79
Cppyy::GetScope
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
Definition: clingwrapper.cxx:497
CPPGetSetItem.h
CPyCppyy::Pythonize
bool Pythonize(PyObject *pyclass, const std::string &name)
Definition: Pythonize.cxx:1011
CPyCppyy::sync_templates
static void sync_templates(PyObject *pyclass, const std::string &mtCppName, const std::string &mtName)
Definition: ProxyWrappers.cxx:126
Cppyy::ExistsMethodTemplate
RPY_EXPORTED bool ExistsMethodTemplate(TCppScope_t scope, const std::string &name)
Definition: clingwrapper.cxx:1604
CPyCppyy::BindCppObject
PyObject * BindCppObject(Cppyy::TCppObject_t object, Cppyy::TCppType_t klass, const unsigned flags=0)
Definition: ProxyWrappers.cxx:876
CPPFunction.h
CPyCppyy::BindCppObjectArray
PyObject * BindCppObjectArray(Cppyy::TCppObject_t address, Cppyy::TCppType_t klass, Py_ssize_t *dims)
Cppyy::TCppIndex_t
size_t TCppIndex_t
Definition: cpp_cppyy.h:24
CPyCppyy::CPPClassMethod
Definition: CPPClassMethod.h:10
Cppyy::GetDatamemberOffset
RPY_EXPORTED intptr_t GetDatamemberOffset(TCppScope_t scope, TCppIndex_t idata)
Definition: clingwrapper.cxx:1895
CPyCppyy::PyStrings::gCppName
R__EXTERN PyObject * gCppName
Definition: TPython.cxx:103
ProxyWrappers.h
CPyCppyy::TemplateProxy
Definition: TemplateProxy.h:50
Cppyy::IsPublicMethod
RPY_EXPORTED bool IsPublicMethod(TCppMethod_t method)
Definition: clingwrapper.cxx:1765
CPyCppyy::TemplateProxy::AdoptTemplate
void AdoptTemplate(PyCallable *pc)
Definition: TemplateProxy.cxx:114
CPyCppyy::CreateScopeProxy
PyObject * CreateScopeProxy(Cppyy::TCppScope_t)
Definition: ProxyWrappers.cxx:490
Cppyy::IsTemplate
RPY_EXPORTED bool IsTemplate(const std::string &template_name)
Definition: clingwrapper.cxx:553
CPyCppyy::CPPInstance::EFlags
EFlags
Definition: CPPInstance.h:28
Cppyy::IsNamespace
RPY_EXPORTED bool IsNamespace(TCppScope_t scope)
Definition: clingwrapper.cxx:923
CPyCppyy::CPPScope_Check
bool CPPScope_Check(T *object)
Definition: CPPScope.h:76
Cppyy::IsTemplatedConstructor
RPY_EXPORTED bool IsTemplatedConstructor(TCppScope_t scope, TCppIndex_t imeth)
Definition: clingwrapper.cxx:1590
CPyCppyy::CPPSmartClass
Definition: CPPScope.h:65
CPyCppyy::CPPGetItem
Definition: CPPGetSetItem.h:22
CPPConstructor.h
CPyCppyy.h
Cppyy::IsPublicData
RPY_EXPORTED bool IsPublicData(TCppScope_t scope, TCppIndex_t idata)
Definition: clingwrapper.cxx:1984
Cppyy::GetNumDatamembers
RPY_EXPORTED TCppIndex_t GetNumDatamembers(TCppScope_t scope)
Definition: clingwrapper.cxx:1811
CPyCppyy::PyStrings::gName
R__EXTERN PyObject * gName
Definition: TPython.cxx:105
Cppyy::GetScopedFinalName
RPY_EXPORTED std::string GetScopedFinalName(TCppType_t type)
Definition: clingwrapper.cxx:1161
CPyCppyy::TemplateProxy_New
TemplateProxy * TemplateProxy_New(const std::string &cppname, const std::string &pyname, PyObject *pyclass)
Definition: TemplateProxy.h:91
CPyCppyy::CPPFunction
Definition: CPPFunction.h:11
CPyCppyy_PyText_AsString
#define CPyCppyy_PyText_AsString
Definition: CPyCppyy.h:97
Cppyy::GetNumBases
RPY_EXPORTED TCppIndex_t GetNumBases(TCppType_t type)
Definition: clingwrapper.cxx:1212
CPyCppyy::CPPScope
Definition: CPPScope.h:37
Cppyy::TCppType_t
TCppScope_t TCppType_t
Definition: cpp_cppyy.h:19
Cppyy::TCppObject_t
void * TCppObject_t
Definition: cpp_cppyy.h:21
CPyCppyy::TemplateProxy::AdoptMethod
void AdoptMethod(PyCallable *pc)
Definition: TemplateProxy.cxx:108
TypeManip.h
Cppyy::GetFinalName
RPY_EXPORTED std::string GetFinalName(TCppType_t type)
Definition: clingwrapper.cxx:1148
Cppyy::TCppMethod_t
intptr_t TCppMethod_t
Definition: cpp_cppyy.h:22
Cppyy::GetMethod
RPY_EXPORTED TCppMethod_t GetMethod(TCppScope_t scope, TCppIndex_t imeth)
Definition: clingwrapper.cxx:1386
CPyCppyy::gPyTypeMap
PyObject * gPyTypeMap
Definition: CPyCppyyModule.cxx:164
fUnderlyingType
Cppyy::TCppType_t fUnderlyingType
Definition: DeclareConverters.h:435
CPPScope.h
CPyCppyy::CPPConstructor
Definition: CPPConstructor.h:10
Cppyy::IsEnum
RPY_EXPORTED bool IsEnum(const std::string &type_name)
Definition: clingwrapper.cxx:943
CPyCppyy::CreateNewCppProxyClass
static PyObject * CreateNewCppProxyClass(Cppyy::TCppScope_t klass, PyObject *pybases)
Definition: ProxyWrappers.cxx:53
Cppyy::GetBaseOffset
RPY_EXPORTED ptrdiff_t GetBaseOffset(TCppType_t derived, TCppType_t base, TCppObject_t address, int direction, bool rerror=false)
Definition: clingwrapper.cxx:1278
fFlags
unsigned int fFlags
Definition: DeclareExecutors.h:98
CPPOverload.h
CPyCppyy::gPinnedTypes
std::set< Cppyy::TCppType_t > gPinnedTypes
Definition: CPyCppyyModule.cxx:171
name
char name[80]
Definition: TGX11.cxx:110
Cppyy::IsMethodTemplate
RPY_EXPORTED bool IsMethodTemplate(TCppScope_t scope, TCppIndex_t imeth)
Definition: clingwrapper.cxx:1618
Cppyy::IsAbstract
RPY_EXPORTED bool IsAbstract(TCppType_t type)
Definition: clingwrapper.cxx:934
Cppyy::GetMethodName
RPY_EXPORTED std::string GetMethodName(TCppMethod_t)
Definition: clingwrapper.cxx:1399
CPyCppyy::CPPOverload
Definition: CPPOverload.h:36
CPyCppyy::Utility::Compound
const std::string Compound(const std::string &name)
Definition: Utility.cxx:782
CPyCppyy::CPPInstance_Type
PyTypeObject CPPInstance_Type
Definition: CPPInstance.cxx:745
CPyCppyy::CPPInstance::SetSmart
void SetSmart(PyObject *smart_type)
Definition: CPPInstance.cxx:168
Cppyy::GetDatamemberName
RPY_EXPORTED std::string GetDatamemberName(TCppScope_t scope, TCppIndex_t idata)
Definition: clingwrapper.cxx:1840
Cppyy::GetNumMethods
RPY_EXPORTED TCppIndex_t GetNumMethods(TCppScope_t scope)
Definition: clingwrapper.cxx:1319
CPyCppyy::CPPIncompleteClassConstructor
Definition: CPPConstructor.h:44
Py_TYPE
#define Py_TYPE(ob)
Definition: CPyCppyy.h:209
Cppyy::GetMethodResultType
RPY_EXPORTED std::string GetMethodResultType(TCppMethod_t)
Definition: clingwrapper.cxx:1429
CPyCppyy::CPPScope::kIsInComplete
@ kIsInComplete
Definition: CPPScope.h:46
Cppyy::IsComplete
RPY_EXPORTED bool IsComplete(const std::string &type_name)
Definition: clingwrapper.cxx:640
CPyCppyy::TemplateProxy_Check
bool TemplateProxy_Check(T *object)
Definition: TemplateProxy.h:79
CPyCppyy::gThisModule
R__EXTERN PyObject * gThisModule
Definition: TPython.cxx:100
CPyCppyy::BindCppObjectNoCast
PyObject * BindCppObjectNoCast(Cppyy::TCppObject_t object, Cppyy::TCppType_t klass, const unsigned flags=0)
Definition: ProxyWrappers.cxx:802
CPyCppyy::CPPAbstractClassConstructor
Definition: CPPConstructor.h:28
CPyCppyy::CPPMethod
Definition: CPPMethod.h:18
PyStrings.h
int
CPPMethod.h