Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
clingwrapper.cxx
Go to the documentation of this file.
1#ifndef WIN32
2#ifndef _CRT_SECURE_NO_WARNINGS
3// silence warnings about getenv, strncpy, etc.
4#define _CRT_SECURE_NO_WARNINGS
5#endif
6#endif
7
8// Bindings
9#include "precommondefs.h"
10#include "cpp_cppyy.h"
11#include "callcontext.h"
12
13// ROOT
14#include "TBaseClass.h"
15#include "TClass.h"
16#include "TClassRef.h"
17#include "TClassTable.h"
18#include "TClassEdit.h"
19#include "TCollection.h"
20#include "TDataMember.h"
21#include "TDataType.h"
22#include "TEnum.h"
23#include "TEnumConstant.h"
24#include "TEnv.h"
25#include "TError.h"
26#include "TException.h"
27#include "TFunction.h"
28#include "TFunctionTemplate.h"
29#include "TGlobal.h"
30#include "THashList.h"
31#include "TInterpreter.h"
32#include "TList.h"
33#include "TListOfDataMembers.h"
34#include "TListOfEnums.h"
35#include "TMethod.h"
36#include "TMethodArg.h"
37#include "TROOT.h"
38#include "TSystem.h"
39#include "TThread.h"
40
41// Standard
42#include <cassert>
43#include <algorithm> // for std::count, std::remove
44#include <climits>
45#include <stdexcept>
46#include <map>
47#include <new>
48#include <set>
49#include <sstream>
50#include <csignal>
51#include <cstdlib> // for getenv
52#include <cstring>
53#include <typeinfo>
54
55// temp
56#include <iostream>
58// --temp
59
60
61// small number that allows use of stack for argument passing
62const int SMALL_ARGS_N = 8;
63
64// convention to pass flag for direct calls (similar to Python's vector calls)
65#define DIRECT_CALL ((size_t)1 << (8 * sizeof(size_t) - 1))
66static inline size_t CALL_NARGS(size_t nargs) {
67 return nargs & ~DIRECT_CALL;
68}
69
70// data for life time management ---------------------------------------------
71typedef std::vector<TClassRef> ClassRefs_t;
73static const ClassRefs_t::size_type GLOBAL_HANDLE = 1;
74static const ClassRefs_t::size_type STD_HANDLE = GLOBAL_HANDLE + 1;
75
76typedef std::map<std::string, ClassRefs_t::size_type> Name2ClassRefIndex_t;
78static std::map<std::string, std::string> resolved_enum_types;
79
80namespace {
81
82static inline
83Cppyy::TCppType_t find_memoized_scope(const std::string& name)
84{
85 auto icr = g_name2classrefidx.find(name);
86 if (icr != g_name2classrefidx.end())
87 return (Cppyy::TCppType_t)icr->second;
88 return (Cppyy::TCppType_t)0;
89}
90
91static inline
92std::string find_memoized_resolved_name(const std::string& name)
93{
94// resolved class types
95 Cppyy::TCppType_t klass = find_memoized_scope(name);
96 if (klass) return Cppyy::GetScopedFinalName(klass);
97
98// resolved enum types
99 auto res = resolved_enum_types.find(name);
100 if (res != resolved_enum_types.end())
101 return res->second;
102
103// unknown ...
104 return "";
105}
106
107class CallWrapper {
108public:
109 typedef const void* DeclId_t;
110
111public:
112 CallWrapper(TFunction* f) : fDecl(f->GetDeclId()), fName(f->GetName()), fTF(new TFunction(*f)) {}
113 CallWrapper(DeclId_t fid, const std::string& n) : fDecl(fid), fName(n), fTF(nullptr) {}
114 ~CallWrapper() {
115 delete fTF;
116 }
117
118public:
120 DeclId_t fDecl;
121 std::string fName;
122 TFunction* fTF;
123};
124
125}
126
127static std::vector<CallWrapper*> gWrapperHolder;
128
129static inline
131{
132 CallWrapper* wrap = new CallWrapper(f);
133 gWrapperHolder.push_back(wrap);
134 return wrap;
135}
136
137static inline
138CallWrapper* new_CallWrapper(CallWrapper::DeclId_t fid, const std::string& n)
139{
140 CallWrapper* wrap = new CallWrapper(fid, n);
141 gWrapperHolder.push_back(wrap);
142 return wrap;
143}
144
145typedef std::vector<TGlobal*> GlobalVars_t;
146typedef std::map<TGlobal*, GlobalVars_t::size_type> GlobalVarsIndices_t;
147
150
151static std::set<std::string> gSTLNames;
152
153
154// data ----------------------------------------------------------------------
156
157// builtin types (including a few common STL templates as long as they live in
158// the global namespace b/c of choices upstream)
159static std::set<std::string> g_builtins =
160 {"bool", "char", "signed char", "unsigned char", "wchar_t", "short", "unsigned short",
161 "int", "unsigned int", "long", "unsigned long", "long long", "unsigned long long",
162 "float", "double", "long double", "void",
163 "allocator", "array", "basic_string", "complex", "initializer_list", "less", "list",
164 "map", "pair", "set", "vector"};
165
166// smart pointer types
167static std::set<std::string> gSmartPtrTypes =
168 {"auto_ptr", "std::auto_ptr", "shared_ptr", "std::shared_ptr",
169 "unique_ptr", "std::unique_ptr", "weak_ptr", "std::weak_ptr"};
170
171// to filter out ROOT names
172static std::set<std::string> gInitialNames;
173static std::set<std::string> gRootSOs;
174
175// configuration
176static bool gEnableFastPath = true;
177
178
179// global initialization -----------------------------------------------------
180namespace {
181
182// names copied from TUnixSystem
183#ifdef WIN32
184const int SIGBUS = 0; // simple placeholders for ones that don't exist
185const int SIGSYS = 0;
186const int SIGPIPE = 0;
187const int SIGQUIT = 0;
188const int SIGWINCH = 0;
189const int SIGALRM = 0;
190const int SIGCHLD = 0;
191const int SIGURG = 0;
192const int SIGUSR1 = 0;
193const int SIGUSR2 = 0;
194#endif
195
196static struct Signalmap_t {
197 int fCode;
198 const char *fSigName;
199} gSignalMap[kMAXSIGNALS] = { // the order of the signals should be identical
200 { SIGBUS, "bus error" }, // to the one in TSysEvtHandler.h
201 { SIGSEGV, "segmentation violation" },
202 { SIGSYS, "bad argument to system call" },
203 { SIGPIPE, "write on a pipe with no one to read it" },
204 { SIGILL, "illegal instruction" },
205 { SIGABRT, "abort" },
206 { SIGQUIT, "quit" },
207 { SIGINT, "interrupt" },
208 { SIGWINCH, "window size change" },
209 { SIGALRM, "alarm clock" },
210 { SIGCHLD, "death of a child" },
211 { SIGURG, "urgent data arrived on an I/O channel" },
212 { SIGFPE, "floating point exception" },
213 { SIGTERM, "termination signal" },
214 { SIGUSR1, "user-defined signal 1" },
215 { SIGUSR2, "user-defined signal 2" }
216};
217
218static void inline do_trace(int sig) {
219 std::cerr << " *** Break *** " << (sig < kMAXSIGNALS ? gSignalMap[sig].fSigName : "") << std::endl;
221}
222
223class TExceptionHandlerImp : public TExceptionHandler {
224public:
225 void HandleException(Int_t sig) override {
226 if (TROOT::Initialized()) {
227 if (gException) {
228 gInterpreter->RewindDictionary();
229 gInterpreter->ClearFileBusy();
230 }
231
232 if (!std::getenv("CPPYY_CRASH_QUIET"))
233 do_trace(sig);
234
235 // jump back, if catch point set
236 Throw(sig);
237 }
238
239 do_trace(sig);
240 gSystem->Exit(128 + sig);
241 }
242};
243
244class ApplicationStarter {
245public:
246 ApplicationStarter() {
247 // initialize ROOT early to guarantee proper order of shutdown later on (gROOT is a
248 // macro that resolves to the ROOT::GetROOT() function call)
249 (void)gROOT;
250
251 // setup dummy holders for global and std namespaces
252 assert(g_classrefs.size() == GLOBAL_HANDLE);
254 g_classrefs.push_back(TClassRef(""));
255
256 // aliases for std (setup already in pythonify)
258 g_name2classrefidx["::std"] = g_name2classrefidx["std"];
259 g_classrefs.push_back(TClassRef("std"));
260
261 // add a dummy global to refer to as null at index 0
262 g_globalvars.push_back(nullptr);
263 g_globalidx[nullptr] = 0;
264
265 // disable fast path if requested
266 if (std::getenv("CPPYY_DISABLE_FASTPATH")) gEnableFastPath = false;
267
268 // fill the set of STL names
269 const char* stl_names[] = {"allocator", "auto_ptr", "bad_alloc", "bad_cast",
270 "bad_exception", "bad_typeid", "basic_filebuf", "basic_fstream", "basic_ifstream",
271 "basic_ios", "basic_iostream", "basic_istream", "basic_istringstream",
272 "basic_ofstream", "basic_ostream", "basic_ostringstream", "basic_streambuf",
273 "basic_string", "basic_stringbuf", "basic_stringstream", "binary_function",
274 "binary_negate", "bitset", "byte", "char_traits", "codecvt_byname", "codecvt", "collate",
275 "collate_byname", "compare", "complex", "ctype_byname", "ctype", "default_delete",
276 "deque", "divides", "domain_error", "equal_to", "exception", "forward_list", "fpos",
277 "function", "greater_equal", "greater", "gslice_array", "gslice", "hash", "indirect_array",
278 "integer_sequence", "invalid_argument", "ios_base", "istream_iterator", "istreambuf_iterator",
279 "istrstream", "iterator_traits", "iterator", "length_error", "less_equal", "less",
280 "list", "locale", "localedef utility", "locale utility", "logic_error", "logical_and",
281 "logical_not", "logical_or", "map", "mask_array", "mem_fun", "mem_fun_ref", "messages",
282 "messages_byname", "minus", "modulus", "money_get", "money_put", "moneypunct",
283 "moneypunct_byname", "multimap", "multiplies", "multiset", "negate", "not_equal_to",
284 "num_get", "num_put", "numeric_limits", "numpunct", "numpunct_byname",
285 "ostream_iterator", "ostreambuf_iterator", "ostrstream", "out_of_range",
286 "overflow_error", "pair", "plus", "pointer_to_binary_function",
287 "pointer_to_unary_function", "priority_queue", "queue", "range_error",
288 "raw_storage_iterator", "reverse_iterator", "runtime_error", "set", "shared_ptr",
289 "slice_array", "slice", "stack", "string", "strstream", "strstreambuf",
290 "time_get_byname", "time_get", "time_put_byname", "time_put", "unary_function",
291 "unary_negate", "unique_ptr", "underflow_error", "unordered_map", "unordered_multimap",
292 "unordered_multiset", "unordered_set", "valarray", "vector", "weak_ptr", "wstring",
293 "__hash_not_enabled"};
294 for (auto& name : stl_names)
295 gSTLNames.insert(name);
296
297 // set opt level (default to 2 if not given; Cling itself defaults to 0)
298 int optLevel = 2;
299 if (std::getenv("CPPYY_OPT_LEVEL")) optLevel = atoi(std::getenv("CPPYY_OPT_LEVEL"));
300 if (optLevel != 0) {
301 std::ostringstream s;
302 s << "#pragma cling optimize " << optLevel;
303 gInterpreter->ProcessLine(s.str().c_str());
304 }
305
306 // load frequently used headers
307 const char* code =
308 "#include <iostream>\n"
309 "#include <string>\n"
310 "#include <DllImport.h>\n" // defines R__EXTERN
311 "#include <vector>\n"
312 "#include <utility>";
313 gInterpreter->ProcessLine(code);
314
315 // create helpers for comparing thingies
316 gInterpreter->Declare(
317 "namespace __cppyy_internal { template<class C1, class C2>"
318 " bool is_equal(const C1& c1, const C2& c2) { return (bool)(c1 == c2); } }");
319 gInterpreter->Declare(
320 "namespace __cppyy_internal { template<class C1, class C2>"
321 " bool is_not_equal(const C1& c1, const C2& c2) { return (bool)(c1 != c2); } }");
322
323 // helper for multiple inheritance
324 gInterpreter->Declare("namespace __cppyy_internal { struct Sep; }");
325
326 // retrieve all initial (ROOT) C++ names in the global scope to allow filtering later
327 if (!std::getenv("CPPYY_NO_ROOT_FILTER")) {
328 gROOT->GetListOfGlobals(true); // force initialize
329 gROOT->GetListOfGlobalFunctions(true); // id.
330 std::set<std::string> initial;
332 gInitialNames = initial;
333
334#ifndef WIN32
335 gRootSOs.insert("libCore.so ");
336 gRootSOs.insert("libRIO.so ");
337 gRootSOs.insert("libThread.so ");
338 gRootSOs.insert("libMathCore.so ");
339#else
340 gRootSOs.insert("libCore.dll ");
341 gRootSOs.insert("libRIO.dll ");
342 gRootSOs.insert("libThread.dll ");
343 gRootSOs.insert("libMathCore.dll ");
344#endif
345 }
346
347 // start off with a reasonable size placeholder for wrappers
348 gWrapperHolder.reserve(1024);
349
350 // create an exception handler to process signals
351 gExceptionHandler = new TExceptionHandlerImp{};
352 }
353
354 ~ApplicationStarter() {
355 for (auto wrap : gWrapperHolder)
356 delete wrap;
357 delete gExceptionHandler; gExceptionHandler = nullptr;
358 }
359} _applicationStarter;
360
361} // unnamed namespace
362
363
364// local helpers -------------------------------------------------------------
365static inline
367{
368 assert((ClassRefs_t::size_type)scope < g_classrefs.size());
369 return g_classrefs[(ClassRefs_t::size_type)scope];
370}
371
372static inline
374 CallWrapper* wrap = ((CallWrapper*)method);
375 if (!wrap->fTF) {
376 MethodInfo_t* mi = gInterpreter->MethodInfo_Factory(wrap->fDecl);
377 wrap->fTF = new TFunction(mi);
378 }
379 return wrap->fTF;
380}
381
382/*
383static inline
384CallWrapper::DeclId_t m2d(Cppyy::TCppMethod_t method) {
385 CallWrapper* wrap = ((CallWrapper*)method);
386 if (!wrap->fTF || wrap->fTF->GetDeclId() != wrap->fDecl) {
387 MethodInfo_t* mi = gInterpreter->MethodInfo_Factory(wrap->fDecl);
388 wrap->fTF = new TFunction(mi);
389 }
390 return wrap->fDecl;
391}
392*/
393
394static inline
395char* cppstring_to_cstring(const std::string& cppstr)
396{
397 char* cstr = (char*)malloc(cppstr.size()+1);
398 memcpy(cstr, cppstr.c_str(), cppstr.size()+1);
399 return cstr;
400}
401
402static inline
403bool match_name(const std::string& tname, const std::string fname)
404{
405// either match exactly, or match the name as template
406 if (fname.rfind(tname, 0) == 0) {
407 if ((tname.size() == fname.size()) ||
408 (tname.size() < fname.size() && fname[tname.size()] == '<'))
409 return true;
410 }
411 return false;
412}
413
414static inline
415bool is_missclassified_stl(const std::string& name)
416{
417 std::string::size_type pos = name.find('<');
418 if (pos != std::string::npos)
419 return gSTLNames.find(name.substr(0, pos)) != gSTLNames.end();
420 return gSTLNames.find(name) != gSTLNames.end();
421}
422
423
424// direct interpreter access -------------------------------------------------
425bool Cppyy::Compile(const std::string& code, bool /*silent*/)
426{
427 return gInterpreter->Declare(code.c_str());
428}
429
431{
432 if (klass && obj && !IsNamespace((TCppScope_t)klass))
433 return gInterpreter->ToString(GetScopedFinalName(klass).c_str(), (void*)obj);
434 return "";
435}
436
437
438// name to opaque C++ scope representation -----------------------------------
439std::string Cppyy::ResolveName(const std::string& cppitem_name)
440{
441// Fully resolve the given name to the final type name.
442
443// try memoized type cache, in case seen before
444 std::string memoized = find_memoized_resolved_name(cppitem_name);
445 if (!memoized.empty()) return memoized;
446
447// remove global scope '::' if present
448 std::string tclean = cppitem_name.compare(0, 2, "::") == 0 ?
449 cppitem_name.substr(2, std::string::npos) : cppitem_name;
450
451// classes (most common)
452 tclean = TClassEdit::CleanType(tclean.c_str());
453 if (tclean.empty() /* unknown, eg. an operator */) return cppitem_name;
454
455// reduce [N] to []
456 if (tclean[tclean.size()-1] == ']')
457 tclean = tclean.substr(0, tclean.rfind('[')) + "[]";
458
459 if (tclean.rfind("byte", 0) == 0 || tclean.rfind("std::byte", 0) == 0)
460 return tclean;
461
462// remove __restrict and __restrict__
463 auto pos = tclean.rfind("__restrict");
464 if (pos != std::string::npos)
465 tclean = tclean.substr(0, pos);
466
467 if (tclean.compare(0, 9, "std::byte") == 0)
468 return tclean;
469
470
471// check data types list (accept only builtins as typedefs will
472// otherwise not be resolved)
473 if (IsBuiltin(tclean)) return tclean;
474// special case for enums
475 if (IsEnum(cppitem_name))
476 return ResolveEnum(cppitem_name);
477
478// special case for clang's builtin __type_pack_element (which does not resolve)
479 pos = cppitem_name.size() > 20 ? \
480 cppitem_name.rfind("__type_pack_element", 5) : std::string::npos;
481 if (pos != std::string::npos) {
482 // shape is "[std::]__type_pack_element<index,type1,type2,...,typeN>cpd": extract
483 // first the index, and from there the indexed type; finally, restore the
484 // qualifiers
485 const char* str = cppitem_name.c_str();
486 char* endptr = nullptr;
487 unsigned long index = strtoul(str+20+pos, &endptr, 0);
488
489 std::string tmplvars{endptr};
490 auto start = tmplvars.find(',') + 1;
491 auto end = tmplvars.find(',', start);
492 while (index != 0) {
493 start = end+1;
494 end = tmplvars.find(',', start);
495 if (end == std::string::npos) end = tmplvars.rfind('>');
496 --index;
497 }
498
499 std::string resolved = tmplvars.substr(start, end-start);
500 auto cpd = tmplvars.rfind('>');
501 if (cpd != std::string::npos && cpd+1 != tmplvars.size())
502 return resolved + tmplvars.substr(cpd+1, std::string::npos);
503 return resolved;
504 }
505
506// typedefs etc. (and a couple of hacks around TClassEdit-isms, fixing of which
507// in ResolveTypedef itself is a TODO ...)
508 tclean = TClassEdit::ResolveTypedef(tclean.c_str(), true);
509 pos = 0;
510 while ((pos = tclean.find("::::", pos)) != std::string::npos) {
511 tclean.replace(pos, 4, "::");
512 pos += 2;
513 }
514
515 if (tclean.compare(0, 6, "const ") != 0)
516 return TClassEdit::ShortType(tclean.c_str(), 2);
517 return "const " + TClassEdit::ShortType(tclean.c_str(), 2);
518}
519
520
521std::string Cppyy::ResolveEnum(const std::string& enum_type)
522{
523// The underlying type of a an enum may be any kind of integer.
524// Resolve that type via a workaround (note: this function assumes
525// that the enum_type name is a valid enum type name)
526 auto res = resolved_enum_types.find(enum_type);
527 if (res != resolved_enum_types.end())
528 return res->second;
529
530// desugar the type before resolving
531 std::string et_short = TClassEdit::ShortType(enum_type.c_str(), 1);
532 if (et_short.find("(unnamed") == std::string::npos) {
533 std::ostringstream decl;
534 // TODO: now presumed fixed with https://sft.its.cern.ch/jira/browse/ROOT-6988
535 for (auto& itype : {"unsigned int"}) {
536 decl << "std::is_same<"
537 << itype
538 << ", std::underlying_type<"
539 << et_short
540 << ">::type>::value;";
541 if (gInterpreter->ProcessLine(decl.str().c_str())) {
542 // TODO: "re-sugaring" like this is brittle, but the top
543 // should be re-translated into AST-based code anyway
544 std::string resugared;
545 if (et_short.size() != enum_type.size()) {
546 auto pos = enum_type.find(et_short);
547 if (pos != std::string::npos) {
548 resugared = enum_type.substr(0, pos) + itype;
549 if (pos+et_short.size() < enum_type.size())
550 resugared += enum_type.substr(pos+et_short.size(), std::string::npos);
551 }
552 }
553 if (resugared.empty()) resugared = itype;
554 resolved_enum_types[enum_type] = resugared;
555 return resugared;
556 }
557 }
558 }
559
560// failed or anonymous ... signal upstream to special case this
561 int ipos = (int)enum_type.size()-1;
562 for (; 0 <= ipos; --ipos) {
563 char c = enum_type[ipos];
564 if (isspace(c)) continue;
565 if (isalnum(c) || c == '_' || c == '>' || c == ')') break;
566 }
567 bool isConst = enum_type.find("const ", 6) != std::string::npos;
568 std::string restype = isConst ? "const " : "";
569 restype += "internal_enum_type_t"+enum_type.substr((std::string::size_type)ipos+1, std::string::npos);
570 resolved_enum_types[enum_type] = restype;
571 return restype; // should default to some int variant
572}
573
574Cppyy::TCppScope_t Cppyy::GetScope(const std::string& sname)
575{
576// First, try cache
577 TCppType_t result = find_memoized_scope(sname);
578 if (result) return result;
579
580// Second, skip builtins before going through the more expensive steps of resolving
581// typedefs and looking up TClass
582 if (g_builtins.find(sname) != g_builtins.end())
583 return (TCppScope_t)0;
584
585// TODO: scope_name should always be final already?
586// Resolve name fully before lookup to make sure all aliases point to the same scope
587 std::string scope_name = ResolveName(sname);
588 bool bHasAlias1 = sname != scope_name;
589 if (bHasAlias1) {
590 result = find_memoized_scope(scope_name);
591 if (result) {
592 g_name2classrefidx[sname] = result;
593 return result;
594 }
595 }
596
597// both failed, but may be STL name that's missing 'std::' now, but didn't before
598 bool b_scope_name_missclassified = is_missclassified_stl(scope_name);
599 if (b_scope_name_missclassified) {
600 result = find_memoized_scope("std::"+scope_name);
601 if (result) g_name2classrefidx["std::"+scope_name] = (ClassRefs_t::size_type)result;
602 }
603 bool b_sname_missclassified = bHasAlias1 ? is_missclassified_stl(sname) : false;
604 if (b_sname_missclassified) {
605 if (!result) result = find_memoized_scope("std::"+sname);
606 if (result) g_name2classrefidx["std::"+sname] = (ClassRefs_t::size_type)result;
607 }
608
609 if (result) return result;
610
611// use TClass directly, to enable auto-loading; class may be stubbed (eg. for
612// function returns) or forward declared, leading to a non-null TClass that is
613// otherwise invalid/unusable
614 TClassRef cr(TClass::GetClass(scope_name.c_str(), true /* load */, true /* silent */));
615 if (!cr.GetClass())
616 return (TCppScope_t)0;
617
618// memoize found/created TClass
619 bool bHasAlias2 = cr->GetName() != scope_name;
620 if (bHasAlias2) {
621 result = find_memoized_scope(cr->GetName());
622 if (result) {
623 g_name2classrefidx[scope_name] = result;
624 if (bHasAlias1) g_name2classrefidx[sname] = result;
625 return result;
626 }
627 }
628
629 ClassRefs_t::size_type sz = g_classrefs.size();
630 g_name2classrefidx[scope_name] = sz;
631 if (bHasAlias1) g_name2classrefidx[sname] = sz;
632 if (bHasAlias2) g_name2classrefidx[cr->GetName()] = sz;
633// TODO: make ROOT/meta NOT remove std :/
634 if (b_scope_name_missclassified)
635 g_name2classrefidx["std::"+scope_name] = sz;
636 if (b_sname_missclassified)
637 g_name2classrefidx["std::"+sname] = sz;
638
639 g_classrefs.push_back(TClassRef(scope_name.c_str()));
640
641 return (TCppScope_t)sz;
642}
643
644bool Cppyy::IsTemplate(const std::string& template_name)
645{
646 return (bool)gInterpreter->CheckClassTemplate(template_name.c_str());
647}
648
649namespace {
650 class AutoCastRTTI {
651 public:
652 virtual ~AutoCastRTTI() {}
653 };
654}
655
657{
658 TClassRef& cr = type_from_handle(klass);
659 if (!cr.GetClass() || !obj) return klass;
660
661 if (!(cr->ClassProperty() & kClassHasVirtual))
662 return klass; // not polymorphic: no RTTI info available
663
664// TODO: ios class casting (ostream, streambuf, etc.) fails with a crash in GetActualClass()
665// below on Mac ARM (it's likely that the found actual class was replaced, maybe because
666// there are duplicates from pcm/pch?); filter them out for now as it's usually unnecessary
667// anyway to autocast these
668 std::string clName = cr->GetName();
669 if (clName.find("std::", 0, 5) == 0 && clName.find("stream") != std::string::npos)
670 return klass;
671
672#ifdef _WIN64
673// Cling does not provide a consistent ImageBase address for calculating relative addresses
674// as used in Windows 64b RTTI. So, check for our own RTTI extension instead. If that fails,
675// see whether the unmangled raw_name is available (e.g. if this is an MSVC compiled rather
676// than JITed class) and pass on if it is.
677 volatile const char* raw = nullptr; // to prevent too aggressive reordering
678 try {
679 // this will filter those objects that do not have RTTI to begin with (throws)
680 AutoCastRTTI* pcst = (AutoCastRTTI*)obj;
681 raw = typeid(*pcst).raw_name();
682
683 // check the signature id (0 == absolute, 1 == relative, 2 == ours)
684 void* vfptr = *(void**)((intptr_t)obj);
685 void* meta = (void*)((intptr_t)*((void**)((intptr_t)vfptr-sizeof(void*))));
686 if (*(intptr_t*)meta == 2) {
687 // access the extra data item which is an absolute pointer to the RTTI
688 void* ptdescr = (void*)((intptr_t)meta + 4*sizeof(unsigned long)+sizeof(void*));
689 if (ptdescr && *(void**)ptdescr) {
690 auto rtti = *(std::type_info**)ptdescr;
691 raw = rtti->raw_name();
692 if (raw && raw[0] != '\0') // likely unnecessary
693 return (TCppType_t)GetScope(rtti->name());
694 }
695
696 return klass; // do not fall through if no RTTI info available
697 }
698
699 // if the raw name is the empty string (no guarantees that this is so as truly, the
700 // address is corrupt, but it is common to be empty), then there is no accessible RTTI
701 // and getting the unmangled name will crash ...
702 if (!raw)
703 return klass;
704 } catch (std::bad_typeid) {
705 return klass; // can't risk passing to ROOT/meta as it may do RTTI
706 }
707#endif
708
709 TClass* clActual = cr->GetActualClass((void*)obj);
710 // The additional check using TClass::GetClassInfo is to prevent returning classes of which the Interpreter has no info
711 if (clActual && clActual != cr.GetClass() && clActual->GetClassInfo()) {
712 auto itt = g_name2classrefidx.find(clActual->GetName());
713 if (itt != g_name2classrefidx.end())
714 return (TCppType_t)itt->second;
715 return (TCppType_t)GetScope(clActual->GetName());
716 }
717
718 return klass;
719}
720
722{
723 TClassRef& cr = type_from_handle(klass);
724 if (cr.GetClass() && cr->GetClassInfo())
725 return (size_t)gInterpreter->ClassInfo_Size(cr->GetClassInfo());
726 return (size_t)0;
727}
728
729size_t Cppyy::SizeOf(const std::string& type_name)
730{
731 TDataType* dt = gROOT->GetType(type_name.c_str());
732 if (dt) return dt->Size();
733 return SizeOf(GetScope(type_name));
734}
735
736
737bool Cppyy::IsBuiltin(const std::string& type_name)
738{
739 if (g_builtins.find(type_name) != g_builtins.end())
740 return true;
741
742 const std::string& tclean = TClassEdit::CleanType(type_name.c_str(), 1);
743 if (g_builtins.find(tclean) != g_builtins.end())
744 return true;
745
746 if (strstr(tclean.c_str(), "std::complex"))
747 return true;
748
749 return false;
750}
751
752bool Cppyy::IsComplete(const std::string& type_name)
753{
754// verify whether the dictionary of this class is fully available
755 bool b = false;
756
757 int oldEIL = gErrorIgnoreLevel;
758 gErrorIgnoreLevel = 3000;
759 TClass* klass = TClass::GetClass(TClassEdit::ShortType(type_name.c_str(), 1).c_str());
760 if (klass && klass->GetClassInfo()) // works for normal case w/ dict
761 b = gInterpreter->ClassInfo_IsLoaded(klass->GetClassInfo());
762 else { // special case for forward declared classes
763 ClassInfo_t* ci = gInterpreter->ClassInfo_Factory(type_name.c_str());
764 if (ci) {
765 b = gInterpreter->ClassInfo_IsLoaded(ci);
766 gInterpreter->ClassInfo_Delete(ci); // we own the fresh class info
767 }
768 }
769 gErrorIgnoreLevel = oldEIL;
770 return b;
771}
772
773// memory management ---------------------------------------------------------
775{
777 return (TCppObject_t)::operator new(gInterpreter->ClassInfo_Size(cr->GetClassInfo()));
778}
779
781{
782 ::operator delete(instance);
783}
784
786{
788 if (arena)
789 return (TCppObject_t)cr->New(arena, TClass::kRealNew);
790 return (TCppObject_t)cr->New(TClass::kRealNew);
791}
792
793static std::map<Cppyy::TCppType_t, bool> sHasOperatorDelete;
795{
798 cr->Destructor((void*)instance);
799 else {
800 ROOT::DelFunc_t fdel = cr->GetDelete();
801 if (fdel) fdel((void*)instance);
802 else {
803 auto ib = sHasOperatorDelete.find(type);
804 if (ib == sHasOperatorDelete.end()) {
805 TFunction *f = (TFunction *)cr->GetMethodAllAny("operator delete");
806 sHasOperatorDelete[type] = (bool)(f && (f->Property() & kIsPublic));
807 ib = sHasOperatorDelete.find(type);
808 }
809 ib->second ? cr->Destructor((void *)instance) : ::operator delete((void *)instance);
810 }
811 }
812}
813
814
815// method/function dispatching -----------------------------------------------
817{
818// TODO: method should be a callfunc, so that no mapping would be needed.
819 CallWrapper* wrap = (CallWrapper*)method;
820
821 CallFunc_t* callf = gInterpreter->CallFunc_Factory();
822 MethodInfo_t* meth = gInterpreter->MethodInfo_Factory(wrap->fDecl);
823 gInterpreter->CallFunc_SetFunc(callf, meth);
824 gInterpreter->MethodInfo_Delete(meth);
825
826 if (!(callf && gInterpreter->CallFunc_IsValid(callf))) {
827 // TODO: propagate this error to caller w/o use of Python C-API
828 /*
829 PyErr_Format(PyExc_RuntimeError, "could not resolve %s::%s(%s)",
830 const_cast<TClassRef&>(klass).GetClassName(),
831 wrap.fName, callString.c_str()); */
832 std::cerr << "TODO: report unresolved function error to Python\n";
833 if (callf) gInterpreter->CallFunc_Delete(callf);
835 }
836
837// generate the wrapper and JIT it; ignore wrapper generation errors (will simply
838// result in a nullptr that is reported upstream if necessary; often, however,
839// there is a different overload available that will do)
840 auto oldErrLvl = gErrorIgnoreLevel;
842 wrap->fFaceptr = gInterpreter->CallFunc_IFacePtr(callf);
843 gErrorIgnoreLevel = oldErrLvl;
844
845 gInterpreter->CallFunc_Delete(callf); // does not touch IFacePtr
846 return wrap->fFaceptr;
847}
848
849static inline
850bool copy_args(Parameter* args, size_t nargs, void** vargs)
851{
852 bool runRelease = false;
853 for (size_t i = 0; i < nargs; ++i) {
854 switch (args[i].fTypeCode) {
855 case 'X': /* (void*)type& with free */
856 runRelease = true;
857 case 'V': /* (void*)type& */
858 vargs[i] = args[i].fValue.fVoidp;
859 break;
860 case 'r': /* const type& */
861 vargs[i] = args[i].fRef;
862 break;
863 default: /* all other types in union */
864 vargs[i] = (void*)&args[i].fValue.fVoidp;
865 break;
866 }
867 }
868 return runRelease;
869}
870
871static inline
872void release_args(Parameter* args, size_t nargs) {
873 for (size_t i = 0; i < nargs; ++i) {
874 if (args[i].fTypeCode == 'X')
875 free(args[i].fValue.fVoidp);
876 }
877}
878
879static inline bool WrapperCall(Cppyy::TCppMethod_t method, size_t nargs, void* args_, void* self, void* result)
880{
881 Parameter* args = (Parameter*)args_;
882 //bool is_direct = nargs & DIRECT_CALL;
883 nargs = CALL_NARGS(nargs);
884
885 CallWrapper* wrap = (CallWrapper*)method;
886 const TInterpreter::CallFuncIFacePtr_t& faceptr = wrap->fFaceptr.fGeneric ? wrap->fFaceptr : GetCallFunc(method);
887 if (!faceptr.fGeneric)
888 return false; // happens with compilation error
889
891 bool runRelease = false;
892 if (nargs <= SMALL_ARGS_N) {
893 void* smallbuf[SMALL_ARGS_N];
894 if (nargs) runRelease = copy_args(args, nargs, smallbuf);
895 faceptr.fGeneric(self, (int)nargs, smallbuf, result);
896 } else {
897 std::vector<void*> buf(nargs);
898 runRelease = copy_args(args, nargs, buf.data());
899 faceptr.fGeneric(self, (int)nargs, buf.data(), result);
900 }
901 if (runRelease) release_args(args, nargs);
902 return true;
903 }
904
906 bool runRelease = false;
907 if (nargs <= SMALL_ARGS_N) {
908 void* smallbuf[SMALL_ARGS_N];
909 if (nargs) runRelease = copy_args(args, nargs, (void**)smallbuf);
910 faceptr.fCtor((void**)smallbuf, result, (unsigned long)nargs);
911 } else {
912 std::vector<void*> buf(nargs);
913 runRelease = copy_args(args, nargs, buf.data());
914 faceptr.fCtor(buf.data(), result, (unsigned long)nargs);
915 }
916 if (runRelease) release_args(args, nargs);
917 return true;
918 }
919
921 std::cerr << " DESTRUCTOR NOT IMPLEMENTED YET! " << std::endl;
922 return false;
923 }
924
925 return false;
926}
927
928template<typename T>
929static inline
930T CallT(Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, size_t nargs, void* args)
931{
932 T t{};
933 if (WrapperCall(method, nargs, args, (void*)self, &t))
934 return t;
935 return (T)-1;
936}
937
938#define CPPYY_IMP_CALL(typecode, rtype) \
939rtype Cppyy::Call##typecode(TCppMethod_t method, TCppObject_t self, size_t nargs, void* args)\
940{ \
941 return CallT<rtype>(method, self, nargs, args); \
942}
943
944void Cppyy::CallV(TCppMethod_t method, TCppObject_t self, size_t nargs, void* args)
945{
946 if (!WrapperCall(method, nargs, args, (void*)self, nullptr))
947 return /* TODO ... report error */;
948}
949
950CPPYY_IMP_CALL(B, unsigned char)
957CPPYY_IMP_CALL(D, double )
959
960void* Cppyy::CallR(TCppMethod_t method, TCppObject_t self, size_t nargs, void* args)
961{
962 void* r = nullptr;
963 if (WrapperCall(method, nargs, args, (void*)self, &r))
964 return r;
965 return nullptr;
966}
967
969 TCppMethod_t method, TCppObject_t self, size_t nargs, void* args, size_t* length)
970{
971 char* cstr = nullptr;
972 TClassRef cr("std::string");
973 std::string* cppresult = (std::string*)malloc(sizeof(std::string));
974 if (WrapperCall(method, nargs, args, self, (void*)cppresult)) {
975 cstr = cppstring_to_cstring(*cppresult);
976 *length = cppresult->size();
977 cppresult->std::string::~basic_string();
978 } else
979 *length = 0;
980 free((void*)cppresult);
981 return cstr;
982}
983
985 TCppMethod_t method, TCppType_t /* klass */, size_t nargs, void* args)
986{
987 void* obj = nullptr;
988 if (WrapperCall(method, nargs, args, nullptr, &obj))
989 return (TCppObject_t)obj;
990 return (TCppObject_t)0;
991}
992
994{
996 cr->Destructor((void*)self, true);
997}
998
1000 TCppObject_t self, size_t nargs, void* args, TCppType_t result_type)
1001{
1002 TClassRef& cr = type_from_handle(result_type);
1003 void* obj = ::operator new(gInterpreter->ClassInfo_Size(cr->GetClassInfo()));
1004 if (WrapperCall(method, nargs, args, self, obj))
1005 return (TCppObject_t)obj;
1006 ::operator delete(obj);
1007 return (TCppObject_t)0;
1008}
1009
1011{
1012 if (check_enabled && !gEnableFastPath) return (TCppFuncAddr_t)nullptr;
1013 TFunction* f = m2f(method);
1014
1015 TCppFuncAddr_t pf = (TCppFuncAddr_t)gInterpreter->FindSym(f->GetMangledName());
1016 if (pf) return pf;
1017
1018 int ierr = 0;
1019 const char* fn = TClassEdit::DemangleName(f->GetMangledName(), ierr);
1020 if (ierr || !fn)
1021 return pf;
1022
1023 // TODO: the following attempts are all brittle and leak transactions, but
1024 // each properly exposes the symbol so subsequent lookups will succeed
1025 if (strstr(f->GetName(), "<")) {
1026 // force explicit instantiation and try again
1027 std::ostringstream sig;
1028 sig << "template " << fn << ";";
1029 gInterpreter->ProcessLine(sig.str().c_str());
1030 } else {
1031 std::ostringstream sig;
1032
1033 std::string sfn = fn;
1034 std::string::size_type pos = sfn.find('(');
1035 if (pos != std::string::npos) sfn = sfn.substr(0, pos);
1036
1037 // start cast
1038 sig << '(' << f->GetReturnTypeName() << " (";
1039
1040 // add scope for methods
1041 pos = sfn.rfind(':');
1042 if (pos != std::string::npos) {
1043 std::string scope_name = sfn.substr(0, pos-1);
1044 TCppScope_t scope = GetScope(scope_name);
1045 if (scope && !IsNamespace(scope))
1046 sig << scope_name << "::";
1047 }
1048
1049 // finalize cast
1050 sig << "*)" << GetMethodSignature(method, false)
1051 << ((f->Property() & kIsConstMethod) ? " const" : "")
1052 << ')';
1053
1054 // load address
1055 sig << '&' << sfn;
1056 gInterpreter->Calc(sig.str().c_str());
1057 }
1058
1059 return (TCppFuncAddr_t)gInterpreter->FindSym(f->GetMangledName());
1060}
1061
1062
1063// handling of function argument buffer --------------------------------------
1065{
1066 return new Parameter[nargs];
1067}
1068
1070{
1071 delete [] (Parameter*)args;
1072}
1073
1075{
1076 return sizeof(Parameter);
1077}
1078
1080{
1081 return offsetof(Parameter, fTypeCode);
1082}
1083
1084
1085// scope reflection information ----------------------------------------------
1087{
1088// Test if this scope represents a namespace.
1089 if (scope == GLOBAL_HANDLE)
1090 return true;
1091 TClassRef& cr = type_from_handle(scope);
1092 if (cr.GetClass())
1093 return cr->Property() & kIsNamespace;
1094 return false;
1095}
1096
1098{
1099// Test if this type may not be instantiated.
1100 TClassRef& cr = type_from_handle(klass);
1101 if (cr.GetClass())
1102 return cr->Property() & kIsAbstract;
1103 return false;
1104}
1105
1106bool Cppyy::IsEnum(const std::string& type_name)
1107{
1108 if (type_name.empty()) return false;
1109 std::string tn_short = TClassEdit::ShortType(type_name.c_str(), 1);
1110 if (tn_short.empty()) return false;
1111 return gInterpreter->ClassInfo_IsEnum(tn_short.c_str());
1112}
1113
1115{
1116// Test if this type is an aggregate type
1117 TClassRef& cr = type_from_handle(klass);
1118 if (cr.GetClass())
1119 return cr->ClassProperty() & kClassIsAggregate;
1120 return false;
1121}
1122
1124{
1125// Test if this type has a default constructor or is a "plain old data" type
1127 if (cr.GetClass())
1128 return cr->HasDefaultConstructor() || (cr->ClassProperty() & kClassIsAggregate);
1129 return true;
1130}
1131
1132// helpers for stripping scope names
1133static
1134std::string outer_with_template(const std::string& name)
1135{
1136// Cut down to the outer-most scope from <name>, taking proper care of templates.
1137 int tpl_open = 0;
1138 for (std::string::size_type pos = 0; pos < name.size(); ++pos) {
1139 std::string::value_type c = name[pos];
1140
1141 // count '<' and '>' to be able to skip template contents
1142 if (c == '<')
1143 ++tpl_open;
1144 else if (c == '>')
1145 --tpl_open;
1146
1147 // collect name up to "::"
1148 else if (tpl_open == 0 && \
1149 c == ':' && pos+1 < name.size() && name[pos+1] == ':') {
1150 // found the extend of the scope ... done
1151 return name.substr(0, pos-1);
1152 }
1153 }
1154
1155// whole name is apparently a single scope
1156 return name;
1157}
1158
1159static
1160std::string outer_no_template(const std::string& name)
1161{
1162// Cut down to the outer-most scope from <name>, drop templates
1163 std::string::size_type first_scope = name.find(':');
1164 if (first_scope == std::string::npos)
1165 return name.substr(0, name.find('<'));
1166 std::string::size_type first_templ = name.find('<');
1167 if (first_templ == std::string::npos)
1168 return name.substr(0, first_scope);
1169 return name.substr(0, std::min(first_templ, first_scope));
1170}
1171
1172#define FILL_COLL(type, filter) { \
1173 TIter itr{coll}; \
1174 type* obj = nullptr; \
1175 while ((obj = (type*)itr.Next())) { \
1176 const char* nm = obj->GetName(); \
1177 if (nm && nm[0] != '_' && !(obj->Property() & (filter))) { \
1178 if (gInitialNames.find(nm) == gInitialNames.end()) \
1179 cppnames.insert(nm); \
1180 }}}
1181
1182static inline
1183void cond_add(Cppyy::TCppScope_t scope, const std::string& ns_scope,
1184 std::set<std::string>& cppnames, const char* name, bool nofilter = false)
1185{
1186 if (!name || name[0] == '_' || strstr(name, ".h") != 0 || strncmp(name, "operator", 8) == 0)
1187 return;
1188
1189 if (scope == GLOBAL_HANDLE) {
1190 std::string to_add = outer_no_template(name);
1191 if ((nofilter || gInitialNames.find(to_add) == gInitialNames.end()) && !is_missclassified_stl(name))
1192 cppnames.insert(outer_no_template(name));
1193 } else if (scope == STD_HANDLE) {
1194 if (strncmp(name, "std::", 5) == 0) {
1195 name += 5;
1196#ifdef __APPLE__
1197 if (strncmp(name, "__1::", 5) == 0) name += 5;
1198#endif
1199 } else if (!is_missclassified_stl(name))
1200 return;
1201 cppnames.insert(outer_no_template(name));
1202 } else {
1203 if (strncmp(name, ns_scope.c_str(), ns_scope.size()) == 0)
1204 cppnames.insert(outer_with_template(name + ns_scope.size()));
1205 }
1206}
1207
1208void Cppyy::GetAllCppNames(TCppScope_t scope, std::set<std::string>& cppnames)
1209{
1210// Collect all known names of C++ entities under scope. This is useful for IDEs
1211// employing tab-completion, for example. Note that functions names need not be
1212// unique as they can be overloaded.
1213 TClassRef& cr = type_from_handle(scope);
1214 if (scope != GLOBAL_HANDLE && !(cr.GetClass() && cr->Property()))
1215 return;
1216
1217 std::string ns_scope = GetFinalName(scope);
1218 if (scope != GLOBAL_HANDLE) ns_scope += "::";
1219
1220// add existing values from read rootmap files if within this scope
1221 TCollection* coll = gInterpreter->GetMapfile()->GetTable();
1222 {
1223 TIter itr{coll};
1224 TEnvRec* ev = nullptr;
1225 while ((ev = (TEnvRec*)itr.Next())) {
1226 // TEnv contains rootmap entries and user-side rootmap files may be already
1227 // loaded on startup. Thus, filter on file name rather than load time.
1228 if (gRootSOs.find(ev->GetValue()) == gRootSOs.end())
1229 cond_add(scope, ns_scope, cppnames, ev->GetName(), true);
1230 }
1231 }
1232
1233// do we care about the class table or are the rootmap and list of types enough?
1234/*
1235 gClassTable->Init();
1236 const int N = gClassTable->Classes();
1237 for (int i = 0; i < N; ++i)
1238 cond_add(scope, ns_scope, cppnames, gClassTable->Next());
1239*/
1240
1241// any other types (e.g. that may have come from parsing headers)
1242 coll = gROOT->GetListOfTypes();
1243 {
1244 TIter itr{coll};
1245 TDataType* dt = nullptr;
1246 while ((dt = (TDataType*)itr.Next())) {
1247 if (!(dt->Property() & kIsFundamental)) {
1248 cond_add(scope, ns_scope, cppnames, dt->GetName());
1249 }
1250 }
1251 }
1252
1253// add functions
1254 coll = (scope == GLOBAL_HANDLE) ?
1255 gROOT->GetListOfGlobalFunctions() : cr->GetListOfMethods();
1256 {
1257 TIter itr{coll};
1258 TFunction* obj = nullptr;
1259 while ((obj = (TFunction*)itr.Next())) {
1260 const char* nm = obj->GetName();
1261 // skip templated functions, adding only the un-instantiated ones
1262 if (nm && nm[0] != '_' && strstr(nm, "<") == 0 && strncmp(nm, "operator", 8) != 0) {
1263 if (gInitialNames.find(nm) == gInitialNames.end())
1264 cppnames.insert(nm);
1265 }
1266 }
1267 }
1268
1269// add uninstantiated templates
1270 coll = (scope == GLOBAL_HANDLE) ?
1271 gROOT->GetListOfFunctionTemplates() : cr->GetListOfFunctionTemplates();
1273
1274// add (global) data members
1275 if (scope == GLOBAL_HANDLE) {
1276 coll = gROOT->GetListOfGlobals();
1278 } else {
1279 coll = cr->GetListOfDataMembers();
1281 coll = cr->GetListOfUsingDataMembers();
1283 }
1284
1285// add enums values only for user classes/namespaces
1286 if (scope != GLOBAL_HANDLE && scope != STD_HANDLE) {
1287 coll = cr->GetListOfEnums();
1289 }
1290
1291#ifdef __APPLE__
1292// special case for Apple, add version namespace '__1' entries to std
1293 if (scope == STD_HANDLE)
1294 GetAllCppNames(GetScope("std::__1"), cppnames);
1295#endif
1296}
1297
1298
1299// class reflection information ----------------------------------------------
1300std::vector<Cppyy::TCppScope_t> Cppyy::GetUsingNamespaces(TCppScope_t scope)
1301{
1302 std::vector<Cppyy::TCppScope_t> res;
1303 if (!IsNamespace(scope))
1304 return res;
1305
1306#ifdef __APPLE__
1307 if (scope == STD_HANDLE) {
1308 res.push_back(GetScope("__1"));
1309 return res;
1310 }
1311#endif
1312
1313 TClassRef& cr = type_from_handle(scope);
1314 if (!cr.GetClass() || !cr->GetClassInfo())
1315 return res;
1316
1317 const std::vector<std::string>& v = gInterpreter->GetUsingNamespaces(cr->GetClassInfo());
1318 res.reserve(v.size());
1319 for (const auto& uid : v) {
1320 Cppyy::TCppScope_t uscope = GetScope(uid);
1321 if (uscope) res.push_back(uscope);
1322 }
1323
1324 return res;
1325}
1326
1327
1328// class reflection information ----------------------------------------------
1330{
1331 if (klass == GLOBAL_HANDLE)
1332 return "";
1333 TClassRef& cr = type_from_handle(klass);
1334 std::string clName = cr->GetName();
1335// TODO: why is this template splitting needed?
1336 std::string::size_type pos = clName.substr(0, clName.find('<')).rfind("::");
1337 if (pos != std::string::npos)
1338 return clName.substr(pos+2, std::string::npos);
1339 return clName;
1340}
1341
1343{
1344 if (klass == GLOBAL_HANDLE)
1345 return "";
1346 TClassRef& cr = type_from_handle(klass);
1347 if (cr.GetClass()) {
1348 std::string name = cr->GetName();
1350 return std::string("std::")+cr->GetName();
1351 return cr->GetName();
1352 }
1353 return "";
1354}
1355
1357{
1358 TClassRef& cr = type_from_handle(klass);
1359 if (!cr.GetClass())
1360 return false;
1361
1362 TFunction* f = cr->GetMethod(("~"+GetFinalName(klass)).c_str(), "");
1363 if (f && (f->Property() & kIsVirtual))
1364 return true;
1365
1366 return false;
1367}
1368
1370{
1371 int is_complex = 1;
1372 size_t nbases = 0;
1373
1374 TClassRef& cr = type_from_handle(klass);
1375 if (cr.GetClass() && cr->GetListOfBases() != 0)
1376 nbases = GetNumBases(klass);
1377
1378 if (1 < nbases)
1379 is_complex = 1;
1380 else if (nbases == 0)
1381 is_complex = 0;
1382 else { // one base class only
1383 TBaseClass* base = (TBaseClass*)cr->GetListOfBases()->At(0);
1384 if (base->Property() & kIsVirtualBase)
1385 is_complex = 1; // TODO: verify; can be complex, need not be.
1386 else
1387 is_complex = HasComplexHierarchy(GetScope(base->GetName()));
1388 }
1389
1390 return is_complex;
1391}
1392
1394{
1395// Get the total number of base classes that this class has.
1396 TClassRef& cr = type_from_handle(klass);
1397 if (cr.GetClass() && cr->GetListOfBases() != 0)
1398 return (TCppIndex_t)cr->GetListOfBases()->GetSize();
1399 return (TCppIndex_t)0;
1400}
1401
1402////////////////////////////////////////////////////////////////////////////////
1403/// \fn Cppyy::TCppIndex_t GetLongestInheritancePath(TClass *klass)
1404/// \brief Retrieve number of base classes in the longest branch of the
1405/// inheritance tree of the input class.
1406/// \param[in] klass The class to start the retrieval process from.
1407///
1408/// This is a helper function for Cppyy::GetNumBasesLongestBranch.
1409/// Given an inheritance tree, the function assigns weight 1 to each class that
1410/// has at least one base. Starting from the input class, the function is
1411/// called recursively on all the bases. For each base the return value is one
1412/// (the weight of the base itself) plus the maximum value retrieved for their
1413/// bases in turn. For example, given the following inheritance tree:
1414///
1415/// ~~~{.cpp}
1416/// class A {}; class B: public A {};
1417/// class X {}; class Y: public X {}; class Z: public Y {};
1418/// class C: public B, Z {};
1419/// ~~~
1420///
1421/// calling this function on an instance of `C` will return 3, the steps
1422/// required to go from C to X.
1424{
1425
1426 auto directbases = klass->GetListOfBases();
1427 if (!directbases) {
1428 // This is a leaf with no bases
1429 return 0;
1430 }
1431 auto ndirectbases = directbases->GetSize();
1432 if (ndirectbases == 0) {
1433 // This is a leaf with no bases
1434 return 0;
1435 } else {
1436 // If there is at least one direct base
1437 std::vector<Cppyy::TCppIndex_t> nbases_branches;
1438 nbases_branches.reserve(ndirectbases);
1439
1440 // Traverse all direct bases of the current class and call the function
1441 // recursively
1442 for (auto baseclass : TRangeDynCast<TBaseClass>(directbases)) {
1443 if (!baseclass)
1444 continue;
1445 if (auto baseclass_tclass = baseclass->GetClassPointer()) {
1447 }
1448 }
1449
1450 // Get longest path among the direct bases of the current class
1451 auto longestbranch = std::max_element(std::begin(nbases_branches), std::end(nbases_branches));
1452
1453 // Add 1 to include the current class in the count
1454 return 1 + *longestbranch;
1455 }
1456}
1457
1458////////////////////////////////////////////////////////////////////////////////
1459/// \fn Cppyy::TCppIndex_t Cppyy::GetNumBasesLongest(TCppType_t klass)
1460/// \brief Retrieve number of base classes in the longest branch of the
1461/// inheritance tree.
1462/// \param[in] klass The class to start the retrieval process from.
1463///
1464/// The function converts the input class to a `TClass *` and calls
1465/// GetLongestInheritancePath.
1467{
1468
1469 const auto &cr = type_from_handle(klass);
1470
1471 if (auto klass_tclass = cr.GetClass()) {
1473 }
1474
1475 // In any other case, return zero
1476 return 0;
1477}
1478
1480{
1482 return ((TBaseClass*)cr->GetListOfBases()->At((int)ibase))->GetName();
1483}
1484
1486{
1487 if (derived == base)
1488 return true;
1491 if (derived_type.GetClass() && base_type.GetClass())
1492 return derived_type->GetBaseClass(base_type) != 0;
1493 return false;
1494}
1495
1497{
1499 const std::string& tn = cr->GetName();
1500 if (gSmartPtrTypes.find(tn.substr(0, tn.find("<"))) != gSmartPtrTypes.end())
1501 return true;
1502 return false;
1503}
1504
1506 const std::string& tname, TCppType_t* raw, TCppMethod_t* deref)
1507{
1508 const std::string& rn = ResolveName(tname);
1509 if (gSmartPtrTypes.find(rn.substr(0, rn.find("<"))) != gSmartPtrTypes.end()) {
1510 if (!raw && !deref) return true;
1511
1513 if (cr.GetClass()) {
1514 TFunction* func = cr->GetMethod("operator->", "");
1515 if (!func) {
1516 gInterpreter->UpdateListOfMethods(cr.GetClass());
1517 func = cr->GetMethod("operator->", "");
1518 }
1519 if (func) {
1520 if (deref) *deref = (TCppMethod_t)new_CallWrapper(func);
1521 if (raw) *raw = GetScope(TClassEdit::ShortType(
1522 func->GetReturnTypeNormalizedName().c_str(), 1));
1523 return (!deref || *deref) && (!raw || *raw);
1524 }
1525 }
1526 }
1527
1528 return false;
1529}
1530
1531void Cppyy::AddSmartPtrType(const std::string& type_name)
1532{
1534}
1535
1536void Cppyy::AddTypeReducer(const std::string& /*reducable*/, const std::string& /*reduced*/)
1537{
1538 // This function is deliberately left empty, because it is not used in
1539 // PyROOT, and synchronizing it with cppyy-backend upstream would require
1540 // patches to ROOT meta.
1541}
1542
1543
1544// type offsets --------------------------------------------------------------
1546 TCppObject_t address, int direction, bool rerror)
1547{
1548// calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0
1549 if (derived == base || !(base && derived))
1550 return (ptrdiff_t)0;
1551
1553 TClassRef& cb = type_from_handle(base);
1554
1555 if (!cd.GetClass() || !cb.GetClass())
1556 return (ptrdiff_t)0;
1557
1558 ptrdiff_t offset = -1;
1559 if (!(cd->GetClassInfo() && cb->GetClassInfo())) { // gInterpreter requirement
1560 // would like to warn, but can't quite determine error from intentional
1561 // hiding by developers, so only cover the case where we really should have
1562 // had a class info, but apparently don't:
1563 if (cd->IsLoaded()) {
1564 // warn to allow diagnostics
1565 std::ostringstream msg;
1566 msg << "failed offset calculation between " << cb->GetName() << " and " << cd->GetName();
1567 // TODO: propagate this warning to caller w/o use of Python C-API
1568 // PyErr_Warn(PyExc_RuntimeWarning, const_cast<char*>(msg.str().c_str()));
1569 std::cerr << "Warning: " << msg.str() << '\n';
1570 }
1571
1572 // return -1 to signal caller NOT to apply offset
1573 return rerror ? (ptrdiff_t)offset : 0;
1574 }
1575
1576 offset = gInterpreter->ClassInfo_GetBaseOffset(
1577 cd->GetClassInfo(), cb->GetClassInfo(), (void*)address, direction > 0);
1578 if (offset == -1) // Cling error, treat silently
1579 return rerror ? (ptrdiff_t)offset : 0;
1580
1581 return (ptrdiff_t)(direction < 0 ? -offset : offset);
1582}
1583
1584
1585// method/function reflection information ------------------------------------
1587{
1589 return (TCppIndex_t)0; // enforce lazy
1590
1591 if (scope == GLOBAL_HANDLE)
1592 return gROOT->GetListOfGlobalFunctions(true)->GetSize();
1593
1595 if (cr.GetClass() && cr->GetListOfMethods(true)) {
1596 Cppyy::TCppIndex_t nMethods = (TCppIndex_t)cr->GetListOfMethods(false)->GetSize();
1597 if (nMethods == (TCppIndex_t)0) {
1598 std::string clName = GetScopedFinalName(scope);
1599 if (clName.find('<') != std::string::npos) {
1600 // chicken-and-egg problem: TClass does not know about methods until
1601 // instantiation, so force it
1602 std::ostringstream stmt;
1603 stmt << "template class " << clName << ";";
1604 gInterpreter->Declare(stmt.str().c_str()/*, silent = true*/);
1605
1606 // now reload the methods
1607 return (TCppIndex_t)cr->GetListOfMethods(true)->GetSize();
1608 }
1609 }
1610 return nMethods;
1611 }
1612
1613 return (TCppIndex_t)0; // unknown class?
1614}
1615
1616std::vector<Cppyy::TCppIndex_t> Cppyy::GetMethodIndicesFromName(
1617 TCppScope_t scope, const std::string& name)
1618{
1619 std::vector<TCppIndex_t> indices;
1621 if (cr.GetClass()) {
1622 gInterpreter->UpdateListOfMethods(cr.GetClass());
1623 int imeth = 0;
1624 TFunction* func = nullptr;
1625 TIter next(cr->GetListOfMethods());
1626 while ((func = (TFunction*)next())) {
1627 if (match_name(name, func->GetName())) {
1628 // C++ functions should be public to allow access; C functions have no access
1629 // specifier and should always be accepted
1630 auto prop = func->Property();
1631 if ((prop & kIsPublic) || !(prop & (kIsPrivate | kIsProtected | kIsPublic)))
1632 indices.push_back((TCppIndex_t)imeth);
1633 }
1634 ++imeth;
1635 }
1636 } else if (scope == GLOBAL_HANDLE) {
1637 TCollection* funcs = gROOT->GetListOfGlobalFunctions(true);
1638
1639 // tickle deserialization
1640 if (!funcs->FindObject(name.c_str()))
1641 return indices;
1642
1643 TFunction* func = nullptr;
1644 TIter ifunc(funcs);
1645 while ((func = (TFunction*)ifunc.Next())) {
1646 if (match_name(name, func->GetName()))
1647 indices.push_back((TCppIndex_t)new_CallWrapper(func));
1648 }
1649 }
1650
1651 return indices;
1652}
1653
1655{
1657 if (cr.GetClass()) {
1658 TFunction* f = (TFunction*)cr->GetListOfMethods(false)->At((int)idx);
1659 if (f) return (Cppyy::TCppMethod_t)new_CallWrapper(f);
1660 return (Cppyy::TCppMethod_t)nullptr;
1661 }
1662
1664 return (Cppyy::TCppMethod_t)idx;
1665}
1666
1668{
1669 if (method) {
1670 const std::string& name = ((CallWrapper*)method)->fName;
1671
1672 if (name.compare(0, 8, "operator") != 0)
1673 // strip template instantiation part, if any
1674 return name.substr(0, name.find('<'));
1675 return name;
1676 }
1677 return "<unknown>";
1678}
1679
1681{
1682 if (method) {
1683 std::string name = ((CallWrapper*)method)->fName;
1684 name.erase(std::remove(name.begin(), name.end(), ' '), name.end());
1685 return name;
1686 }
1687 return "<unknown>";
1688}
1689
1691{
1692 if (method)
1693 return m2f(method)->GetMangledName();
1694 return "<unknown>";
1695}
1696
1698{
1699 if (method) {
1700 TFunction* f = m2f(method);
1701 if (f->ExtraProperty() & kIsConstructor)
1702 return "constructor";
1703 std::string restype = f->GetReturnTypeName();
1704 // TODO: this is ugly; GetReturnTypeName() keeps typedefs, but may miss scopes
1705 // for some reason; GetReturnTypeNormalizedName() has been modified to return
1706 // the canonical type to guarantee correct namespaces. Sometimes typedefs look
1707 // better, sometimes not, sometimes it's debatable (e.g. vector<int>::size_type).
1708 // So, for correctness sake, GetReturnTypeNormalizedName() is used, except for a
1709 // special case of uint8_t/int8_t that must propagate as their typedefs.
1710 if (restype.find("int8_t") != std::string::npos)
1711 return restype;
1712 restype = f->GetReturnTypeNormalizedName();
1713 if (restype == "(lambda)") {
1714 std::ostringstream s;
1715 // TODO: what if there are parameters to the lambda?
1716 s << "__cling_internal::FT<decltype("
1717 << GetMethodFullName(method) << "(";
1718 for (Cppyy::TCppIndex_t i = 0; i < Cppyy::GetMethodNumArgs(method); ++i) {
1719 if (i != 0) s << ", ";
1720 s << Cppyy::GetMethodArgType(method, i) << "{}";
1721 }
1722 s << "))>::F";
1723 TClass* cl = TClass::GetClass(s.str().c_str());
1724 if (cl) return cl->GetName();
1725 // TODO: signal some type of error (or should that be upstream?
1726 }
1727 return restype;
1728 }
1729 return "<unknown>";
1730}
1731
1733{
1734 if (method)
1735 return m2f(method)->GetNargs();
1736 return 0;
1737}
1738
1740{
1741 if (method) {
1742 TFunction* f = m2f(method);
1743 return (TCppIndex_t)(f->GetNargs() - f->GetNargsOpt());
1744 }
1745 return (TCppIndex_t)0;
1746}
1747
1749{
1750 if (method) {
1751 TFunction* f = m2f(method);
1752 TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At((int)iarg);
1753 return arg->GetName();
1754 }
1755 return "<unknown>";
1756}
1757
1759{
1760 if (method) {
1761 TFunction* f = m2f(method);
1762 TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At((int)iarg);
1763 std::string ft = arg->GetFullTypeName();
1764 if (ft.rfind("enum ", 0) != std::string::npos) { // special case to preserve 'enum' tag
1765 std::string arg_type = arg->GetTypeNormalizedName();
1766 return arg_type.insert(arg_type.rfind("const ", 0) == std::string::npos ? 0 : 6, "enum ");
1767 } else if (g_builtins.find(ft) != g_builtins.end() || ft.find("int8_t") != std::string::npos)
1768 return ft; // do not resolve int8_t and uint8_t typedefs
1769
1770 return arg->GetTypeNormalizedName();
1771 }
1772 return "<unknown>";
1773}
1774
1776{
1777 if (method) {
1778 TFunction* f = m2f(method);
1779 TMethodArg* arg = (TMethodArg *)f->GetListOfMethodArgs()->At((int)iarg);
1780 void *argqtp = gInterpreter->TypeInfo_QualTypePtr(arg->GetTypeInfo());
1781
1782 TypeInfo_t *reqti = gInterpreter->TypeInfo_Factory(req_type.c_str());
1783 void *reqqtp = gInterpreter->TypeInfo_QualTypePtr(reqti);
1784
1785 // This scoring is not based on any particular rules
1786 if (gInterpreter->IsSameType(argqtp, reqqtp))
1787 return 0; // Best match
1788 else if ((gInterpreter->IsSignedIntegerType(argqtp) && gInterpreter->IsSignedIntegerType(reqqtp)) ||
1789 (gInterpreter->IsUnsignedIntegerType(argqtp) && gInterpreter->IsUnsignedIntegerType(reqqtp)) ||
1790 (gInterpreter->IsFloatingType(argqtp) && gInterpreter->IsFloatingType(reqqtp)))
1791 return 1;
1792 else if ((gInterpreter->IsSignedIntegerType(argqtp) && gInterpreter->IsUnsignedIntegerType(reqqtp)) ||
1793 (gInterpreter->IsFloatingType(argqtp) && gInterpreter->IsUnsignedIntegerType(reqqtp)))
1794 return 2;
1795 else if ((gInterpreter->IsIntegerType(argqtp) && gInterpreter->IsIntegerType(reqqtp)))
1796 return 3;
1797 else if ((gInterpreter->IsVoidPointerType(argqtp) && gInterpreter->IsPointerType(reqqtp)))
1798 return 4;
1799 else
1800 return 10; // Penalize heavily for no possible match
1801 }
1802 return INT_MAX; // Method is not valid
1803}
1804
1806{
1807 if (method) {
1808 TFunction* f = m2f(method);
1809 TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At((int)iarg);
1810 const char* def = arg->GetDefault();
1811 if (def)
1812 return def;
1813 }
1814
1815 return "";
1816}
1817
1819{
1820 TFunction* f = m2f(method);
1821 if (f) {
1822 std::ostringstream sig;
1823 sig << "(";
1824 int nArgs = f->GetNargs();
1825 if (maxargs != (TCppIndex_t)-1) nArgs = std::min(nArgs, (int)maxargs);
1826 for (int iarg = 0; iarg < nArgs; ++iarg) {
1827 TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At(iarg);
1828 sig << arg->GetFullTypeName();
1829 if (show_formalargs) {
1830 const char* argname = arg->GetName();
1831 if (argname && argname[0] != '\0') sig << " " << argname;
1832 const char* defvalue = arg->GetDefault();
1833 if (defvalue && defvalue[0] != '\0') sig << " = " << defvalue;
1834 }
1835 if (iarg != nArgs-1) sig << (show_formalargs ? ", " : ",");
1836 }
1837 sig << ")";
1838 return sig.str();
1839 }
1840 return "<unknown>";
1841}
1842
1844{
1845 std::string scName = GetScopedFinalName(scope);
1846 TFunction* f = m2f(method);
1847 if (f) {
1848 std::ostringstream sig;
1849 sig << f->GetReturnTypeName() << " "
1850 << scName << "::" << f->GetName();
1852 return sig.str();
1853 }
1854 return "<unknown>";
1855}
1856
1858{
1859 if (method) {
1860 TFunction* f = m2f(method);
1861 return f->Property() & kIsConstMethod;
1862 }
1863 return false;
1864}
1865
1867{
1869 return (TCppIndex_t)0; // enforce lazy
1870
1871 if (scope == GLOBAL_HANDLE) {
1872 TCollection* coll = gROOT->GetListOfFunctionTemplates();
1873 if (coll) return (TCppIndex_t)coll->GetSize();
1874 } else {
1876 if (cr.GetClass()) {
1877 TCollection* coll = cr->GetListOfFunctionTemplates(true);
1878 if (coll) return (TCppIndex_t)coll->GetSize();
1879 }
1880 }
1881
1882// failure ...
1883 return (TCppIndex_t)0;
1884}
1885
1887{
1889 return ((THashList*)gROOT->GetListOfFunctionTemplates())->At((int)imeth)->GetName();
1890 else {
1892 if (cr.GetClass())
1893 return cr->GetListOfFunctionTemplates(false)->At((int)imeth)->GetName();
1894 }
1895
1896// failure ...
1897 assert(!"should not be called unless GetNumTemplatedMethods() succeeded");
1898 return "";
1899}
1900
1902{
1904 return false;
1905
1907 if (cr.GetClass()) {
1908 TFunctionTemplate* f = (TFunctionTemplate*)cr->GetListOfFunctionTemplates(false)->At((int)imeth);
1909 return f->ExtraProperty() & kIsConstructor;
1910 }
1911
1912 return false;
1913}
1914
1916{
1918 return (bool)gROOT->GetFunctionTemplate(name.c_str());
1919 else {
1921 if (cr.GetClass())
1922 return (bool)cr->GetFunctionTemplate(name.c_str());
1923 }
1924
1925// failure ...
1926 return false;
1927}
1928
1930{
1931 TFunctionTemplate* tf = nullptr;
1933 tf = gROOT->GetFunctionTemplate(name.c_str());
1934 else {
1936 if (cr.GetClass())
1937 tf = cr->GetFunctionTemplate(name.c_str());
1938 }
1939
1940 if (!tf) return false;
1941
1942 return (bool)(tf->Property() & kIsStatic);
1943}
1944
1946{
1948 if (cr.GetClass()) {
1949 TFunction* f = (TFunction*)cr->GetListOfMethods(false)->At((int)idx);
1950 if (f && strstr(f->GetName(), "<")) return true;
1951 return false;
1952 }
1953
1955 if (((CallWrapper*)idx)->fName.find('<') != std::string::npos) return true;
1956 return false;
1957}
1958
1959// helpers for Cppyy::GetMethodTemplate()
1960static std::map<TDictionary::DeclId_t, CallWrapper*> gMethodTemplates;
1961
1962static inline
1963void remove_space(std::string& n) {
1964 std::string::iterator pos = std::remove_if(n.begin(), n.end(), isspace);
1965 n.erase(pos, n.end());
1966}
1967
1968static inline
1969bool template_compare(std::string n1, std::string n2) {
1970 if (n1.back() == '>') n1 = n1.substr(0, n1.size()-1);
1973 return n2.compare(0, n1.size(), n1) == 0;
1974}
1975
1977 TCppScope_t scope, const std::string& name, const std::string& proto)
1978{
1979// There is currently no clean way of extracting a templated method out of ROOT/meta
1980// for a variety of reasons, none of them fundamental. The game played below is to
1981// first get any pre-existing functions already managed by ROOT/meta, but if that fails,
1982// to do an explicit lookup that ignores the prototype (i.e. the full name should be
1983// enough), and finally to ignore the template arguments part of the name as this fails
1984// in cling if there are default parameters.
1985 TFunction* func = nullptr; ClassInfo_t* cl = nullptr;
1987 func = gROOT->GetGlobalFunctionWithPrototype(name.c_str(), proto.c_str());
1988 if (func && name.back() == '>') {
1989 // make sure that all template parameters match (more are okay, e.g. defaults or
1990 // ones derived from the arguments or variadic templates)
1991 if (!template_compare(name, func->GetName()))
1992 func = nullptr; // happens if implicit conversion matches the overload
1993 }
1994 } else {
1996 if (cr.GetClass()) {
1997 func = cr->GetMethodWithPrototype(name.c_str(), proto.c_str());
1998 if (!func) {
1999 cl = cr->GetClassInfo();
2000 // try base classes to cover a common 'using' case (TODO: this is stupid and misses
2001 // out on base classes; fix that with improved access to Cling)
2003 for (TCppIndex_t i = 0; i < nbases; ++i) {
2005 if (base.GetClass()) {
2006 func = base->GetMethodWithPrototype(name.c_str(), proto.c_str());
2007 if (func) break;
2008 }
2009 }
2010 }
2011 }
2012 }
2013
2014 if (!func && name.back() == '>' && (cl || scope == (TCppScope_t)GLOBAL_HANDLE)) {
2015 // try again, ignoring proto in case full name is complete template
2016 auto declid = gInterpreter->GetFunction(cl, name.c_str());
2017 if (declid) {
2018 auto existing = gMethodTemplates.find(declid);
2019 if (existing == gMethodTemplates.end()) {
2020 auto cw = new_CallWrapper(declid, name);
2021 existing = gMethodTemplates.insert(std::make_pair(declid, cw)).first;
2022 }
2023 return (TCppMethod_t)existing->second;
2024 }
2025 }
2026
2027 if (func) {
2028 // make sure we didn't match a non-templated overload
2029 if (func->ExtraProperty() & kIsTemplateSpec)
2030 return (TCppMethod_t)new_CallWrapper(func);
2031
2032 // disregard this non-templated method as it will be considered when appropriate
2033 return (TCppMethod_t)nullptr;
2034 }
2035
2036// try again with template arguments removed from name, if applicable
2037 if (name.back() == '>') {
2038 auto pos = name.find('<');
2039 if (pos != std::string::npos) {
2041 if (cppmeth) {
2042 // allow if requested template names match up to the result
2043 const std::string& alt = GetMethodFullName(cppmeth);
2044 if (name.size() < alt.size() && alt.find('<') == pos) {
2046 return cppmeth;
2047 }
2048 }
2049 }
2050 }
2051
2052// failure ...
2053 return (TCppMethod_t)nullptr;
2054}
2055
2056static inline
2057std::string type_remap(const std::string& n1, const std::string& n2)
2058{
2059// Operator lookups of (C++ string, Python str) should succeed for the combos of
2060// string/str, wstring/str, string/unicode and wstring/unicode; since C++ does not have a
2061// operator+(std::string, std::wstring), we'll have to look up the same type and rely on
2062// the converters in CPyCppyy/_cppyy.
2063 if (n1 == "str" || n1 == "unicode") {
2064 if (n2 == "std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >")
2065 return n2; // match like for like
2066 return "std::string"; // probably best bet
2067 } else if (n1 == "float") {
2068 return "double"; // debatable, but probably intended
2069 } else if (n1 == "complex") {
2070 return "std::complex<double>";
2071 }
2072 return n1;
2073}
2074
2076 TCppType_t scope, const std::string& lc, const std::string& rc, const std::string& opname)
2077{
2078// Find a global operator function with a matching signature; prefer by-ref, but
2079// fall back on by-value if that fails.
2080 std::string lcname1 = TClassEdit::CleanType(lc.c_str());
2081 const std::string& rcname = rc.empty() ? rc : type_remap(TClassEdit::CleanType(rc.c_str()), lcname1);
2082 const std::string& lcname = type_remap(lcname1, rcname);
2083
2084 std::string proto = lcname + "&" + (rc.empty() ? rc : (", " + rcname + "&"));
2086 TFunction* func = gROOT->GetGlobalFunctionWithPrototype(opname.c_str(), proto.c_str());
2087 if (func) return (TCppIndex_t)new_CallWrapper(func);
2088 proto = lcname + (rc.empty() ? rc : (", " + rcname));
2089 func = gROOT->GetGlobalFunctionWithPrototype(opname.c_str(), proto.c_str());
2090 if (func) return (TCppIndex_t)new_CallWrapper(func);
2091 } else {
2093 if (cr.GetClass()) {
2094 TFunction* func = cr->GetMethodWithPrototype(opname.c_str(), proto.c_str());
2095 if (func) return (TCppIndex_t)cr->GetListOfMethods()->IndexOf(func);
2096 proto = lcname + (rc.empty() ? rc : (", " + rcname));
2097 func = cr->GetMethodWithPrototype(opname.c_str(), proto.c_str());
2098 if (func) return (TCppIndex_t)cr->GetListOfMethods()->IndexOf(func);
2099 }
2100 }
2101
2102// failure ...
2103 return (TCppIndex_t)-1;
2104}
2105
2106// method properties ---------------------------------------------------------
2107
2109{
2110 if (!method)
2111 return false;
2112 TFunction *f = m2f(method);
2113 return f->Property() & prop;
2114}
2115
2117{
2118 if (!method)
2119 return false;
2120 TFunction *f = m2f(method);
2121 return f->ExtraProperty() & prop;
2122}
2123
2128
2133
2138
2143
2148
2153
2154// data member reflection information ----------------------------------------
2156{
2158 return (TCppIndex_t)0; // enforce lazy
2159
2160 if (scope == GLOBAL_HANDLE)
2161 return gROOT->GetListOfGlobals(true)->GetSize();
2162
2164 if (cr.GetClass() && cr->GetListOfDataMembers())
2165 return cr->GetListOfDataMembers()->GetSize();
2166
2167 return (TCppIndex_t)0; // unknown class?
2168}
2169
2171{
2173 if (cr.GetClass()) {
2174 TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata);
2175 return m->GetName();
2176 }
2179 return gbl->GetName();
2180}
2181
2182static inline
2183int count_scopes(const std::string& tpname)
2184{
2185 int count = 0;
2186 std::string::size_type pos = tpname.find("::", 0);
2187 while (pos != std::string::npos) {
2188 count++;
2189 pos = tpname.find("::", pos+1);
2190 }
2191 return count;
2192}
2193
2195{
2196 if (scope == GLOBAL_HANDLE) {
2198 std::string fullType = gbl->GetFullTypeName();
2199
2200 if ((int)gbl->GetArrayDim()) {
2201 std::ostringstream s;
2202 for (int i = 0; i < (int)gbl->GetArrayDim(); ++i)
2203 s << '[' << gbl->GetMaxIndex(i) << ']';
2204 fullType.append(s.str());
2205 }
2206 return fullType;
2207 }
2208
2210 if (cr.GetClass()) {
2211 TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata);
2212 // TODO: fix this upstream ... Usually, we want m->GetFullTypeName(), because it
2213 // does not resolve typedefs, but it looses scopes for inner classes/structs, it
2214 // doesn't resolve constexpr (leaving unresolved names), leaves spurious "struct"
2215 // or "union" in the name, and can not handle anonymous unions. In that case
2216 // m->GetTrueTypeName() should be used. W/o clear criteria to determine all these
2217 // cases, the general rules are to prefer the true name if the full type does not
2218 // exist as a type for classes, and the most scoped name otherwise.
2219 const char* ft = m->GetFullTypeName(); std::string fullType = ft ? ft : "";
2220 const char* tn = m->GetTrueTypeName(); std::string trueName = tn ? tn : "";
2221 if (!trueName.empty() && fullType != trueName && !IsBuiltin(trueName)) {
2222 if ( (!TClass::GetClass(fullType.c_str()) && TClass::GetClass(trueName.c_str())) || \
2224 bool is_enum_tag = fullType.rfind("enum ", 0) != std::string::npos;
2226 if (is_enum_tag)
2227 fullType.insert(fullType.rfind("const ", 0) == std::string::npos ? 0 : 6, "enum ");
2228 }
2229 }
2230
2231 if ((int)m->GetArrayDim()) {
2232 std::ostringstream s;
2233 for (int i = 0; i < (int)m->GetArrayDim(); ++i)
2234 s << '[' << m->GetMaxIndex(i) << ']';
2235 fullType.append(s.str());
2236 }
2237 return fullType;
2238 }
2239
2240 return "<unknown>";
2241}
2242
2244{
2245 if (scope == GLOBAL_HANDLE) {
2247 if (!gbl->GetAddress() || gbl->GetAddress() == (void*)-1) {
2248 // CLING WORKAROUND: make sure variable is loaded
2249 intptr_t addr = (intptr_t)gInterpreter->ProcessLine((std::string("&")+gbl->GetName()+";").c_str());
2250 if (gbl->GetAddress() && gbl->GetAddress() != (void*)-1)
2251 return (intptr_t)gbl->GetAddress(); // now loaded!
2252 return addr; // last resort ...
2253 }
2254 return (intptr_t)gbl->GetAddress();
2255 }
2256
2258 if (cr.GetClass()) {
2259 TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata);
2260 // CLING WORKAROUND: the following causes templates to be instantiated first within the proper
2261 // scope, making the lookup succeed and preventing spurious duplicate instantiations later. Also,
2262 // if the variable is not yet loaded, pull it in through gInterpreter.
2263 intptr_t offset = (intptr_t)-1;
2264 if (m->Property() & kIsStatic) {
2265 if (strchr(cr->GetName(), '<'))
2266 gInterpreter->ProcessLine(((std::string)cr->GetName()+"::"+m->GetName()+";").c_str());
2267 offset = (intptr_t)m->GetOffsetCint(); // yes, CINT (GetOffset() is both wrong
2268 // and caches that wrong result!
2269 if (offset == (intptr_t)-1)
2270 return (intptr_t)gInterpreter->ProcessLine((std::string("&")+cr->GetName()+"::"+m->GetName()+";").c_str());
2271 } else
2272 offset = (intptr_t)m->GetOffsetCint(); // yes, CINT, see above
2273 return offset;
2274 }
2275
2276 return (intptr_t)-1;
2277}
2278
2279static inline
2281{
2282 if (!gb) return (Cppyy::TCppIndex_t)-1;
2283
2284 auto pidx = g_globalidx.find(gb);
2285 if (pidx == g_globalidx.end()) {
2286 auto idx = g_globalvars.size();
2287 g_globalvars.push_back(gb);
2288 g_globalidx[gb] = idx;
2289 return (Cppyy::TCppIndex_t)idx;
2290 }
2291 return (Cppyy::TCppIndex_t)pidx->second;
2292}
2293
2295{
2296 if (scope == GLOBAL_HANDLE) {
2297 TGlobal* gb = (TGlobal*)gROOT->GetListOfGlobals(false /* load */)->FindObject(name.c_str());
2298 if (!gb) gb = (TGlobal*)gROOT->GetListOfGlobals(true /* load */)->FindObject(name.c_str());
2299 if (!gb) {
2300 // some enums are not loaded as they are not considered part of
2301 // the global scope, but of the enum scope; get them w/o checking
2302 TDictionary::DeclId_t did = gInterpreter->GetDataMember(nullptr, name.c_str());
2303 if (did) {
2304 DataMemberInfo_t* t = gInterpreter->DataMemberInfo_Factory(did, nullptr);
2305 ((TListOfDataMembers*)gROOT->GetListOfGlobals())->Get(t, true);
2306 gb = (TGlobal*)gROOT->GetListOfGlobals(false /* load */)->FindObject(name.c_str());
2307 }
2308 }
2309
2310 if (gb && strcmp(gb->GetFullTypeName(), "(lambda)") == 0) {
2311 // lambdas use a compiler internal closure type, so we wrap
2312 // them, then return the wrapper's type
2313 // TODO: this current leaks the std::function; also, if possible,
2314 // should instantiate through TClass rather then ProcessLine
2315 std::ostringstream s;
2316 s << "auto __cppyy_internal_wrap_" << name << " = "
2317 "new __cling_internal::FT<decltype(" << name << ")>::F"
2318 "{" << name << "};";
2319 gInterpreter->ProcessLine(s.str().c_str());
2320 TGlobal* wrap = (TGlobal*)gROOT->GetListOfGlobals(true)->FindObject(
2321 ("__cppyy_internal_wrap_"+name).c_str());
2322 if (wrap && wrap->GetAddress()) gb = wrap;
2323 }
2324
2325 return gb2idx(gb);
2326
2327 } else {
2329 if (cr.GetClass()) {
2330 TDataMember* dm =
2331 (TDataMember*)cr->GetListOfDataMembers()->FindObject(name.c_str());
2332 // TODO: turning this into an index is silly ...
2333 if (dm) return (TCppIndex_t)cr->GetListOfDataMembers()->IndexOf(dm);
2334 }
2335 }
2336
2337 return (TCppIndex_t)-1;
2338}
2339
2341{
2342 if (scope == GLOBAL_HANDLE) {
2343 TGlobal* gb = (TGlobal*)((THashList*)gROOT->GetListOfGlobals(false /* load */))->At((int)idata);
2344 return gb2idx(gb);
2345 }
2346
2347 return idata;
2348}
2349
2350
2351// data member properties ----------------------------------------------------
2353{
2354 if (scope == GLOBAL_HANDLE)
2355 return true;
2357 if (cr->Property() & kIsNamespace)
2358 return true;
2359 TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata);
2360 return m->Property() & kIsPublic;
2361}
2362
2364{
2365 if (scope == GLOBAL_HANDLE)
2366 return true;
2368 if (cr->Property() & kIsNamespace)
2369 return true;
2370 TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata);
2371 return m->Property() & kIsProtected;
2372}
2373
2375{
2376 if (scope == GLOBAL_HANDLE)
2377 return true;
2379 if (cr->Property() & kIsNamespace)
2380 return true;
2381 TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata);
2382 return m->Property() & kIsStatic;
2383}
2384
2386{
2387 Long_t property = 0;
2388 if (scope == GLOBAL_HANDLE) {
2390 property = gbl->Property();
2391 }
2393 if (cr.GetClass()) {
2394 TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata);
2395 property = m->Property();
2396 }
2397
2398// if the data type is const, but the data member is a pointer/array, the data member
2399// itself is not const; alternatively it is a pointer that is constant
2400 return ((property & kIsConstant) && !(property & (kIsPointer | kIsArray))) || (property & kIsConstPointer);
2401}
2402
2404{
2405// TODO: currently, ROOT/meta does not properly distinguish between variables of enum
2406// type, and values of enums. The latter are supposed to be const. This code relies on
2407// odd features (bugs?) to figure out the difference, but this should really be fixed
2408// upstream and/or deserves a new API.
2409
2410 if (scope == GLOBAL_HANDLE) {
2412
2413 // make use of an oddity: enum global variables do not have their kIsStatic bit
2414 // set, whereas enum global values do
2415 return (gbl->Property() & kIsEnum) && (gbl->Property() & kIsStatic);
2416 }
2417
2419 if (cr.GetClass()) {
2420 TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata);
2421 std::string ti = m->GetTypeName();
2422
2423 // can't check anonymous enums by type name, so just accept them as enums
2424 if (ti.rfind("(anonymous)") != std::string::npos || ti.rfind("(unnamed)") != std::string::npos)
2425 return m->Property() & kIsEnum;
2426
2427 // since there seems to be no distinction between data of enum type and enum values,
2428 // check the list of constants for the type to see if there's a match
2429 if (ti.rfind(cr->GetName(), 0) != std::string::npos) {
2430 std::string::size_type s = strlen(cr->GetName())+2;
2431 if (s < ti.size()) {
2432 TEnum* ee = ((TListOfEnums*)cr->GetListOfEnums())->GetObject(ti.substr(s, std::string::npos).c_str());
2433 if (ee) return ee->GetConstant(m->GetName());
2434 }
2435 }
2436 }
2437
2438// this default return only means that the data will be writable, not that it will
2439// be unreadable or otherwise misrepresented
2440 return false;
2441}
2442
2444{
2445 if (scope == GLOBAL_HANDLE) {
2447 return gbl->GetMaxIndex(dimension);
2448 }
2450 if (cr.GetClass()) {
2451 TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata);
2452 return m->GetMaxIndex(dimension);
2453 }
2454 return -1;
2455}
2456
2457
2458// enum properties -----------------------------------------------------------
2460{
2461 if (scope == GLOBAL_HANDLE)
2462 return (TCppEnum_t)gROOT->GetListOfEnums(kTRUE)->FindObject(enum_name.c_str());
2463
2465 if (cr.GetClass())
2466 return (TCppEnum_t)cr->GetListOfEnums(kTRUE)->FindObject(enum_name.c_str());
2467
2468 return (TCppEnum_t)0;
2469}
2470
2472{
2473 return (TCppIndex_t)((TEnum*)etype)->GetConstants()->GetSize();
2474}
2475
2477{
2478 return ((TEnumConstant*)((TEnum*)etype)->GetConstants()->At((int)idata))->GetName();
2479}
2480
2482{
2483 TEnumConstant* ecst = (TEnumConstant*)((TEnum*)etype)->GetConstants()->At((int)idata);
2484 return (long long)ecst->GetValue();
2485}
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
static Roo_reg_AGKInteg1D instance
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:59
long Long_t
Signed long integer 4 bytes (long). Size depends on architecture.
Definition RtypesCore.h:68
long double LongDouble_t
Long Double (not portable)
Definition RtypesCore.h:75
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:83
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
@ kMAXSIGNALS
Definition Rtypes.h:60
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
EFunctionProperty
@ kIsDestructor
@ kIsTemplateSpec
@ kIsConstructor
@ kClassIsAggregate
@ kClassHasVirtual
@ kClassHasExplicitDtor
@ kClassHasImplicitDtor
EProperty
Definition TDictionary.h:64
@ kIsPublic
Definition TDictionary.h:75
@ kIsPointer
Definition TDictionary.h:78
@ kIsConstant
Definition TDictionary.h:88
@ kIsConstMethod
Definition TDictionary.h:96
@ kIsEnum
Definition TDictionary.h:68
@ kIsPrivate
Definition TDictionary.h:77
@ kIsConstPointer
Definition TDictionary.h:90
@ kIsFundamental
Definition TDictionary.h:70
@ kIsAbstract
Definition TDictionary.h:71
@ kIsArray
Definition TDictionary.h:79
@ kIsStatic
Definition TDictionary.h:80
@ kIsExplicit
Definition TDictionary.h:94
@ kIsProtected
Definition TDictionary.h:76
@ kIsVirtual
Definition TDictionary.h:72
@ kIsNamespace
Definition TDictionary.h:95
@ kIsVirtualBase
Definition TDictionary.h:89
constexpr Int_t kFatal
Definition TError.h:50
Int_t gErrorIgnoreLevel
errors with level below this value will be ignored. Default is kUnset.
Definition TError.cxx:33
R__EXTERN TExceptionHandler * gExceptionHandler
Definition TException.h:79
R__EXTERN ExceptionContext_t * gException
Definition TException.h:69
R__EXTERN void Throw(int code)
If an exception context has been set (using the TRY and RETRY macros) jump back to where it was set.
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 r
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 prop
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 char Point_t Rectangle_t WindowAttributes_t index
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 length
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 req_type
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void funcs
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t property
char name[80]
Definition TGX11.cxx:110
#define gInterpreter
#define gROOT
Definition TROOT.h:411
R__EXTERN TSystem * gSystem
Definition TSystem.h:572
static struct Signalmap_t gSignalMap[kMAXSIGNALS]
const char * proto
Definition civetweb.c:18822
#define free
Definition civetweb.c:1578
#define malloc
Definition civetweb.c:1575
const_iterator begin() const
const_iterator end() const
Each class (see TClass) has a linked list of its base class(es).
Definition TBaseClass.h:33
Long_t Property() const override
Get property description word. For meaning of bits see EProperty.
TClassRef is used to implement a permanent reference to a TClass object.
Definition TClassRef.h:29
TClass * GetClass() const
Definition TClassRef.h:67
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
TList * GetListOfUsingDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of using declarations of a class.
Definition TClass.cxx:3813
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition TClass.cxx:5017
TMethod * GetMethod(const char *method, const char *params, Bool_t objectIsConst=kFALSE)
Find the best method (if there is one) matching the parameters.
Definition TClass.cxx:4438
TMethod * GetMethodWithPrototype(const char *method, const char *proto, Bool_t objectIsConst=kFALSE, ROOT::EFunctionMatchMode mode=ROOT::kConversionMatch)
Find the method with a given prototype.
Definition TClass.cxx:4483
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition TClass.cxx:5439
TList * GetListOfFunctionTemplates(Bool_t load=kTRUE)
Return TListOfFunctionTemplates for a class.
Definition TClass.cxx:3825
TList * GetListOfEnums(Bool_t load=kTRUE)
Return a list containing the TEnums of a class.
Definition TClass.cxx:3713
TList * GetListOfMethods(Bool_t load=kTRUE)
Return list containing the TMethods of a class.
Definition TClass.cxx:3839
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition TClass.cxx:3797
@ kRealNew
Definition TClass.h:110
TList * GetListOfBases()
Return list containing the TBaseClass(es) of a class.
Definition TClass.cxx:3663
Bool_t IsLoaded() const
Return true if the shared library of this class is currently in the a process's memory.
Definition TClass.cxx:5954
ClassInfo_t * GetClassInfo() const
Definition TClass.h:445
Long_t ClassProperty() const
Return the C++ property of this class, eg.
Definition TClass.cxx:2401
Long_t Property() const override
Returns the properties of the TClass as a bit field stored as a Long_t value.
Definition TClass.cxx:6128
Bool_t HasDefaultConstructor(Bool_t testio=kFALSE) const
Return true if we have access to a constructor usable for I/O.
Definition TClass.cxx:7490
TMethod * GetMethodAllAny(const char *method)
Return pointer to method without looking at parameters.
Definition TClass.cxx:4411
ROOT::DelFunc_t GetDelete() const
Return the wrapper around delete ThisObject.
Definition TClass.cxx:7568
TClass * GetActualClass(const void *object) const
Return a pointer to the real class of the object.
Definition TClass.cxx:2612
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2973
Collection abstract base class.
Definition TCollection.h:65
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
All ROOT classes may have RTTI (run time type identification) support added.
Definition TDataMember.h:31
Basic data type descriptor (datatype information is obtained from CINT).
Definition TDataType.h:44
Int_t GetType() const
Definition TDataType.h:68
Long_t Property() const override
Get property description word. For meaning of bits see EProperty.
Int_t Size() const
Get size of basic typedef'ed type.
const void * DeclId_t
The TEnumConstant class implements the constants of the enum type.
The TEnum class implements the enum type.
Definition TEnum.h:33
Definition TEnv.h:86
const char * GetValue() const
Definition TEnv.h:110
const char * GetName() const override
Returns name of object.
Definition TEnv.h:109
Dictionary for function template This class describes one single function template.
Global functions class (global functions are obtained from CINT).
Definition TFunction.h:30
Long_t Property() const override
Get property description word. For meaning of bits see EProperty.
Long_t ExtraProperty() const
Get property description word. For meaning of bits see EProperty.
std::string GetReturnTypeNormalizedName() const
Get the normalized name of the return type.
Global variables class (global variables are obtained from CINT).
Definition TGlobal.h:28
THashList implements a hybrid collection class consisting of a hash table and a list to store TObject...
Definition THashList.h:34
A collection of TDataMember objects designed for fast access given a DeclId_t and for keep track of T...
A collection of TEnum objects designed for fast access given a DeclId_t and for keep track of TEnum t...
TObject * At(Int_t idx) const override
Returns the object at position idx. Returns 0 if idx is out of range.
Definition TList.cxx:354
Each ROOT method (see TMethod) has a linked list of its arguments.
Definition TMethodArg.h:36
const char * GetFullTypeName() const
Get full type description of method argument, e.g.: "class TDirectory*".
TypeInfo_t * GetTypeInfo() const
Get the TypeInfo of the method argument.
const char * GetDefault() const
Get default value of method argument.
std::string GetTypeNormalizedName() const
Get the normalized name of the return type.
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:457
virtual TObject * FindObject(const char *name) const
Must be redefined in derived classes.
Definition TObject.cxx:421
static Bool_t Initialized()
Return kTRUE if the TROOT object has been initialized.
Definition TROOT.cxx:2913
virtual void Exit(int code, Bool_t mode=kTRUE)
Exit the application.
Definition TSystem.cxx:725
virtual void StackTrace()
Print a stack trace.
Definition TSystem.cxx:743
static void cond_add(Cppyy::TCppScope_t scope, const std::string &ns_scope, std::set< std::string > &cppnames, const char *name, bool nofilter=false)
static bool testMethodProperty(Cppyy::TCppMethod_t method, EProperty prop)
static Name2ClassRefIndex_t g_name2classrefidx
#define FILL_COLL(type, filter)
static void remove_space(std::string &n)
const int SMALL_ARGS_N
static std::string outer_with_template(const std::string &name)
static std::string outer_no_template(const std::string &name)
static std::string type_remap(const std::string &n1, const std::string &n2)
static std::map< Cppyy::TCppType_t, bool > sHasOperatorDelete
static std::set< std::string > gRootSOs
static bool template_compare(std::string n1, std::string n2)
static TClassRef & type_from_handle(Cppyy::TCppScope_t scope)
static bool copy_args(Parameter *args, size_t nargs, void **vargs)
static TInterpreter::CallFuncIFacePtr_t GetCallFunc(Cppyy::TCppMethod_t method)
CPyCppyy::Parameter Parameter
static bool is_missclassified_stl(const std::string &name)
std::map< std::string, ClassRefs_t::size_type > Name2ClassRefIndex_t
static const ClassRefs_t::size_type STD_HANDLE
static std::set< std::string > gSmartPtrTypes
static GlobalVars_t g_globalvars
static char * cppstring_to_cstring(const std::string &cppstr)
static void release_args(Parameter *args, size_t nargs)
static std::set< std::string > g_builtins
static std::vector< CallWrapper * > gWrapperHolder
static bool gEnableFastPath
static ClassRefs_t g_classrefs(1)
static bool WrapperCall(Cppyy::TCppMethod_t method, size_t nargs, void *args_, void *self, void *result)
static std::map< std::string, std::string > resolved_enum_types
static Cppyy::TCppIndex_t gb2idx(TGlobal *gb)
static size_t CALL_NARGS(size_t nargs)
static CallWrapper * new_CallWrapper(TFunction *f)
static std::set< std::string > gSTLNames
static const ClassRefs_t::size_type GLOBAL_HANDLE
static GlobalVarsIndices_t g_globalidx
static bool testMethodExtraProperty(Cppyy::TCppMethod_t method, EFunctionProperty prop)
static int count_scopes(const std::string &tpname)
std::vector< TGlobal * > GlobalVars_t
std::map< TGlobal *, GlobalVars_t::size_type > GlobalVarsIndices_t
std::vector< TClassRef > ClassRefs_t
static std::map< TDictionary::DeclId_t, CallWrapper * > gMethodTemplates
static bool match_name(const std::string &tname, const std::string fname)
static TFunction * m2f(Cppyy::TCppMethod_t method)
#define CPPYY_IMP_CALL(typecode, rtype)
static std::set< std::string > gInitialNames
static T CallT(Cppyy::TCppMethod_t method, Cppyy::TCppObject_t self, size_t nargs, void *args)
Cppyy::TCppIndex_t GetLongestInheritancePath(TClass *klass)
Retrieve number of base classes in the longest branch of the inheritance tree of the input class.
const Int_t n
Definition legend1.C:16
#define I(x, y, z)
#define H(x, y, z)
size_t TCppIndex_t
Definition cpp_cppyy.h:40
RPY_EXPORTED TCppIndex_t GetNumTemplatedMethods(TCppScope_t scope, bool accept_namespace=false)
RPY_EXPORTED std::string GetMethodMangledName(TCppMethod_t)
RPY_EXPORTED TCppObject_t CallO(TCppMethod_t method, TCppObject_t self, size_t nargs, void *args, TCppType_t result_type)
RPY_EXPORTED TCppIndex_t CompareMethodArgType(TCppMethod_t, TCppIndex_t iarg, const std::string &req_type)
RPY_EXPORTED ptrdiff_t GetBaseOffset(TCppType_t derived, TCppType_t base, TCppObject_t address, int direction, bool rerror=false)
RPY_EXPORTED void DeallocateFunctionArgs(void *args)
RPY_EXPORTED bool IsEnumData(TCppScope_t scope, TCppIndex_t idata)
RPY_EXPORTED bool IsAbstract(TCppType_t type)
RPY_EXPORTED size_t SizeOf(TCppType_t klass)
RPY_EXPORTED TCppObject_t CallConstructor(TCppMethod_t method, TCppType_t type, size_t nargs, void *args)
intptr_t TCppMethod_t
Definition cpp_cppyy.h:38
RPY_EXPORTED void * AllocateFunctionArgs(size_t nargs)
RPY_EXPORTED bool IsDefaultConstructable(TCppType_t type)
RPY_EXPORTED bool IsTemplate(const std::string &template_name)
RPY_EXPORTED TCppIndex_t GetDatamemberIndexEnumerated(TCppScope_t scope, TCppIndex_t idata)
RPY_EXPORTED TCppIndex_t GetMethodReqArgs(TCppMethod_t)
RPY_EXPORTED bool IsEnum(const std::string &type_name)
RPY_EXPORTED std::vector< TCppIndex_t > GetMethodIndicesFromName(TCppScope_t scope, const std::string &name)
RPY_EXPORTED bool ExistsMethodTemplate(TCppScope_t scope, const std::string &name)
RPY_EXPORTED TCppIndex_t GetNumDatamembers(TCppScope_t scope, bool accept_namespace=false)
RPY_EXPORTED std::string ToString(TCppType_t klass, TCppObject_t obj)
RPY_EXPORTED std::string GetMethodName(TCppMethod_t)
RPY_EXPORTED bool IsConstData(TCppScope_t scope, TCppIndex_t idata)
RPY_EXPORTED void AddSmartPtrType(const std::string &)
RPY_EXPORTED bool Compile(const std::string &code, bool silent=false)
RPY_EXPORTED void CallDestructor(TCppType_t type, TCppObject_t self)
RPY_EXPORTED TCppScope_t gGlobalScope
Definition cpp_cppyy.h:69
RPY_EXPORTED bool IsProtectedData(TCppScope_t scope, TCppIndex_t idata)
RPY_EXPORTED std::string GetMethodSignature(TCppMethod_t, bool show_formalargs, TCppIndex_t maxargs=(TCppIndex_t) -1)
RPY_EXPORTED int GetDimensionSize(TCppScope_t scope, TCppIndex_t idata, int dimension)
RPY_EXPORTED bool IsSubtype(TCppType_t derived, TCppType_t base)
RPY_EXPORTED TCppMethod_t GetMethodTemplate(TCppScope_t scope, const std::string &name, const std::string &proto)
void * TCppObject_t
Definition cpp_cppyy.h:37
RPY_EXPORTED bool IsConstructor(TCppMethod_t method)
RPY_EXPORTED TCppIndex_t GetNumMethods(TCppScope_t scope, bool accept_namespace=false)
RPY_EXPORTED TCppObject_t Construct(TCppType_t type, void *arena=nullptr)
RPY_EXPORTED bool GetSmartPtrInfo(const std::string &, TCppType_t *raw, TCppMethod_t *deref)
RPY_EXPORTED std::string GetMethodArgName(TCppMethod_t, TCppIndex_t iarg)
RPY_EXPORTED size_t GetFunctionArgTypeoffset()
RPY_EXPORTED TCppObject_t Allocate(TCppType_t type)
RPY_EXPORTED void Destruct(TCppType_t type, TCppObject_t instance)
RPY_EXPORTED std::string ResolveName(const std::string &cppitem_name)
TCppScope_t TCppType_t
Definition cpp_cppyy.h:35
RPY_EXPORTED void AddTypeReducer(const std::string &reducable, const std::string &reduced)
RPY_EXPORTED std::string ResolveEnum(const std::string &enum_type)
RPY_EXPORTED long long GetEnumDataValue(TCppEnum_t, TCppIndex_t idata)
RPY_EXPORTED bool IsAggregate(TCppType_t type)
RPY_EXPORTED TCppIndex_t GetMethodNumArgs(TCppMethod_t)
RPY_EXPORTED TCppType_t GetActualClass(TCppType_t klass, TCppObject_t obj)
RPY_EXPORTED std::string GetBaseName(TCppType_t type, TCppIndex_t ibase)
RPY_EXPORTED bool IsNamespace(TCppScope_t scope)
void * TCppEnum_t
Definition cpp_cppyy.h:36
RPY_EXPORTED std::string GetScopedFinalName(TCppType_t type)
RPY_EXPORTED void Deallocate(TCppType_t type, TCppObject_t instance)
RPY_EXPORTED bool IsPublicData(TCppScope_t scope, TCppIndex_t idata)
RPY_EXPORTED std::string GetMethodArgType(TCppMethod_t, TCppIndex_t iarg)
RPY_EXPORTED std::string GetEnumDataName(TCppEnum_t, TCppIndex_t idata)
RPY_EXPORTED void GetAllCppNames(TCppScope_t scope, std::set< std::string > &cppnames)
RPY_EXPORTED bool IsComplete(const std::string &type_name)
RPY_EXPORTED bool IsBuiltin(const std::string &type_name)
RPY_EXPORTED bool IsStaticMethod(TCppMethod_t method)
RPY_EXPORTED TCppIndex_t GetDatamemberIndex(TCppScope_t scope, const std::string &name)
RPY_EXPORTED void CallV(TCppMethod_t method, TCppObject_t self, size_t nargs, void *args)
RPY_EXPORTED bool IsStaticData(TCppScope_t scope, TCppIndex_t idata)
RPY_EXPORTED std::string GetDatamemberType(TCppScope_t scope, TCppIndex_t idata)
RPY_EXPORTED TCppMethod_t GetMethod(TCppScope_t scope, TCppIndex_t imeth)
RPY_EXPORTED bool IsStaticTemplate(TCppScope_t scope, const std::string &name)
RPY_EXPORTED bool IsDestructor(TCppMethod_t method)
RPY_EXPORTED bool IsSmartPtr(TCppType_t type)
RPY_EXPORTED std::string GetTemplatedMethodName(TCppScope_t scope, TCppIndex_t imeth)
RPY_EXPORTED size_t GetFunctionArgSizeof()
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
RPY_EXPORTED bool HasVirtualDestructor(TCppType_t type)
RPY_EXPORTED bool IsConstMethod(TCppMethod_t)
RPY_EXPORTED bool HasComplexHierarchy(TCppType_t type)
RPY_EXPORTED std::vector< TCppScope_t > GetUsingNamespaces(TCppScope_t)
size_t TCppScope_t
Definition cpp_cppyy.h:34
RPY_EXPORTED bool IsTemplatedConstructor(TCppScope_t scope, TCppIndex_t imeth)
RPY_EXPORTED TCppIndex_t GetGlobalOperator(TCppType_t scope, const std::string &lc, const std::string &rc, const std::string &op)
RPY_EXPORTED TCppFuncAddr_t GetFunctionAddress(TCppMethod_t method, bool check_enabled=true)
RPY_EXPORTED TCppIndex_t GetNumEnumData(TCppEnum_t)
RPY_EXPORTED TCppIndex_t GetNumBases(TCppType_t type)
RPY_EXPORTED TCppIndex_t GetNumBasesLongestBranch(TCppType_t type)
RPY_EXPORTED std::string GetMethodPrototype(TCppScope_t scope, TCppMethod_t, bool show_formalargs)
RPY_EXPORTED std::string GetMethodResultType(TCppMethod_t)
RPY_EXPORTED std::string GetFinalName(TCppType_t type)
RPY_EXPORTED char * CallS(TCppMethod_t method, TCppObject_t self, size_t nargs, void *args, size_t *length)
RPY_EXPORTED bool IsExplicit(TCppMethod_t method)
RPY_EXPORTED std::string GetMethodArgDefault(TCppMethod_t, TCppIndex_t iarg)
RPY_EXPORTED bool IsMethodTemplate(TCppScope_t scope, TCppIndex_t imeth)
RPY_EXPORTED std::string GetDatamemberName(TCppScope_t scope, TCppIndex_t idata)
RPY_EXPORTED bool IsPublicMethod(TCppMethod_t method)
RPY_EXPORTED intptr_t GetDatamemberOffset(TCppScope_t scope, TCppIndex_t idata)
void * TCppFuncAddr_t
Definition cpp_cppyy.h:41
RPY_EXPORTED std::string GetMethodFullName(TCppMethod_t)
RPY_EXPORTED bool IsProtectedMethod(TCppMethod_t method)
RPY_EXPORTED TCppEnum_t GetEnum(TCppScope_t scope, const std::string &enum_name)
void(* DelFunc_t)(void *)
Definition Rtypes.h:117
std::string ResolveTypedef(const char *tname, bool resolveAll=false)
std::string CleanType(const char *typeDesc, int mode=0, const char **tail=nullptr)
Cleanup type description, redundant blanks removed and redundant tail ignored return *tail = pointer ...
std::string ShortType(const char *typeDesc, int mode)
Return the absolute type of typeDesc.
char * DemangleName(const char *mangled_name, int &errorCode)
Definition TClassEdit.h:255
union CPyCppyy::Parameter::Value fValue
const char * fSigName
TMarker m
Definition textangle.C:8