Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RDFUtils.cxx
Go to the documentation of this file.
1// Author: Enrico Guiraud, Danilo Piparo CERN 03/2017
2
3/*************************************************************************
4 * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
11#include "RConfigure.h" // R__USE_IMT
12#include "ROOT/RDataSource.hxx"
15#include "ROOT/RDF/Utils.hxx"
16#include "ROOT/RLogger.hxx"
17#include "RtypesCore.h"
18#include "TBranch.h"
19#include "TBranchElement.h"
20#include "TClass.h"
21#include "TClassEdit.h"
22#include "TClassRef.h"
23#include "TError.h" // Info
24#include "TInterpreter.h"
25#include "TLeaf.h"
26#include "TROOT.h" // IsImplicitMTEnabled, GetThreadPoolSize
27#include "TTree.h"
28
29#include <stdexcept>
30#include <string>
31#include <cstring>
32#include <typeinfo>
33
34using namespace ROOT::Detail::RDF;
35using namespace ROOT::RDF;
36
38{
39 static ROOT::Experimental::RLogChannel c("ROOT.RDF");
40 return c;
41}
42
43namespace {
44using TypeInfoRef = std::reference_wrapper<const std::type_info>;
45struct TypeInfoRefHash {
46 std::size_t operator()(TypeInfoRef id) const { return id.get().hash_code(); }
47};
48
49struct TypeInfoRefEqualComp {
50 bool operator()(TypeInfoRef left, TypeInfoRef right) const { return left.get() == right.get(); }
51};
52} // namespace
53
54namespace ROOT {
55namespace Internal {
56namespace RDF {
57
58/// Return the type_info associated to a name. If the association fails, an
59/// exception is thrown.
60/// References and pointers are not supported since those cannot be stored in
61/// columns.
62const std::type_info &TypeName2TypeID(const std::string &name)
63{
64
65 const static std::unordered_map<std::string, TypeInfoRef> typeName2TypeIDMap{
66 {"char", typeid(char)},
67 {"Char_t", typeid(char)},
68 {"unsigned char", typeid(unsigned char)},
69 {"UChar_t", typeid(unsigned char)},
70 {"int", typeid(int)},
71 {"Int_t", typeid(int)},
72 {"unsigned", typeid(unsigned int)},
73 {"unsigned int", typeid(unsigned int)},
74 {"UInt_t", typeid(unsigned int)},
75 {"short", typeid(short)},
76 {"short int", typeid(short)},
77 {"Short_t", typeid(short)},
78 {"unsigned short", typeid(unsigned short)},
79 {"unsigned short int", typeid(unsigned short)},
80 {"UShort_t", typeid(unsigned short)},
81 {"long", typeid(long)},
82 {"long int", typeid(long)},
83 {"Long_t", typeid(long)},
84 {"unsigned long", typeid(unsigned long)},
85 {"unsigned long int", typeid(unsigned long)},
86 {"ULong_t", typeid(unsigned long)},
87 {"double", typeid(double)},
88 {"Double_t", typeid(double)},
89 {"float", typeid(float)},
90 {"Float_t", typeid(float)},
91 {"long long", typeid(long long)},
92 {"long long int", typeid(long long)},
93 {"Long64_t", typeid(long long)},
94 {"unsigned long long", typeid(unsigned long long)},
95 {"unsigned long long int", typeid(unsigned long long)},
96 {"ULong64_t", typeid(unsigned long long)},
97 {"bool", typeid(bool)},
98 {"Bool_t", typeid(bool)}};
99
100 if (auto it = typeName2TypeIDMap.find(name); it != typeName2TypeIDMap.end())
101 return it->second.get();
102
103 if (auto c = TClass::GetClass(name.c_str())) {
104 if (!c->GetTypeInfo()) {
105 throw std::runtime_error("Cannot extract type_info of type " + name + ".");
106 }
107 return *c->GetTypeInfo();
108 }
109
110 throw std::runtime_error("Cannot extract type_info of type " + name + ".");
111}
112
113/// Returns the name of a type starting from its type_info
114/// An empty string is returned in case of failure
115/// References and pointers are not supported since those cannot be stored in
116/// columns.
117/// Note that this function will take a lock and may be a potential source of
118/// contention in multithreaded execution.
119std::string TypeID2TypeName(const std::type_info &id)
120{
121 const static std::unordered_map<TypeInfoRef, std::string, TypeInfoRefHash, TypeInfoRefEqualComp> typeID2TypeNameMap{
122 {typeid(char), "char"}, {typeid(unsigned char), "unsigned char"},
123 {typeid(int), "int"}, {typeid(unsigned int), "unsigned int"},
124 {typeid(short), "short"}, {typeid(unsigned short), "unsigned short"},
125 {typeid(long), "long"}, {typeid(unsigned long), "unsigned long"},
126 {typeid(double), "double"}, {typeid(float), "float"},
127 {typeid(Long64_t), "Long64_t"}, {typeid(ULong64_t), "ULong64_t"},
128 {typeid(bool), "bool"}};
129
130 if (auto it = typeID2TypeNameMap.find(id); it != typeID2TypeNameMap.end())
131 return it->second;
132
133 if (auto c = TClass::GetClass(id)) {
134 return c->GetName();
135 }
136
137 return "";
138}
139
140std::string ComposeRVecTypeName(const std::string &valueType)
141{
142 return "ROOT::VecOps::RVec<" + valueType + ">";
143}
144
145std::string GetLeafTypeName(TLeaf *leaf, const std::string &colName)
146{
147 const char *colTypeCStr = leaf->GetTypeName();
148 std::string colType = colTypeCStr == nullptr ? "" : colTypeCStr;
149 if (colType.empty())
150 throw std::runtime_error("Could not deduce type of leaf " + colName);
151 if (leaf->GetLeafCount() != nullptr && leaf->GetLenStatic() == 1) {
152 // this is a variable-sized array
153 colType = ComposeRVecTypeName(colType);
154 } else if (leaf->GetLeafCount() == nullptr && leaf->GetLenStatic() > 1) {
155 // this is a fixed-sized array (we do not differentiate between variable- and fixed-sized arrays)
156 colType = ComposeRVecTypeName(colType);
157 } else if (leaf->GetLeafCount() != nullptr && leaf->GetLenStatic() > 1) {
158 // we do not know how to deal with this branch
159 throw std::runtime_error("TTree leaf " + colName +
160 " has both a leaf count and a static length. This is not supported.");
161 }
162
163 return colType;
164}
165
166/// Return the typename of object colName stored in t, if any. Return an empty string if colName is not in t.
167/// Supported cases:
168/// - leaves corresponding to single values, variable- and fixed-length arrays, with following syntax:
169/// - "leafname", as long as TTree::GetLeaf resolves it
170/// - "b1.b2...leafname", as long as TTree::GetLeaf("b1.b2....", "leafname") resolves it
171/// - TBranchElements, as long as TTree::GetBranch resolves their names
172std::string GetBranchOrLeafTypeName(TTree &t, const std::string &colName)
173{
174 // look for TLeaf either with GetLeaf(colName) or with GetLeaf(branchName, leafName) (splitting on last dot)
175 auto *leaf = t.GetLeaf(colName.c_str());
176 if (!leaf)
177 leaf = t.FindLeaf(colName.c_str()); // try harder
178 if (!leaf) {
179 // try splitting branchname and leafname
180 const auto dotPos = colName.find_last_of('.');
181 const auto hasDot = dotPos != std::string::npos;
182 if (hasDot) {
183 const auto branchName = colName.substr(0, dotPos);
184 const auto leafName = colName.substr(dotPos + 1);
185 leaf = t.GetLeaf(branchName.c_str(), leafName.c_str());
186 }
187 }
188 if (leaf)
189 return GetLeafTypeName(leaf, std::string(leaf->GetFullName()));
190
191 // we could not find a leaf named colName, so we look for a branch called like this
192 auto branch = t.GetBranch(colName.c_str());
193 if (!branch)
194 branch = t.FindBranch(colName.c_str()); // try harder
195 if (branch) {
196 static const TClassRef tbranchelement("TBranchElement");
197 if (branch->InheritsFrom(tbranchelement)) {
198 auto be = static_cast<TBranchElement *>(branch);
199 if (auto currentClass = be->GetCurrentClass())
200 return currentClass->GetName();
201 else {
202 // Here we have a special case for getting right the type of data members
203 // of classes sorted in TClonesArrays: ROOT-9674
204 auto mother = be->GetMother();
205 if (mother && mother->InheritsFrom(tbranchelement) && mother != be) {
206 auto beMom = static_cast<TBranchElement *>(mother);
207 auto beMomClass = beMom->GetClass();
208 if (beMomClass && 0 == std::strcmp("TClonesArray", beMomClass->GetName()))
209 return be->GetTypeName();
210 }
211 return be->GetClassName();
212 }
213 } else if (branch->IsA() == TBranch::Class() && branch->GetListOfLeaves()->GetEntriesUnsafe() == 1) {
214 // normal branch (not a TBranchElement): if it has only one leaf, we pick the type of the leaf:
215 // RDF and TTreeReader allow referring to branch.leaf as just branch if branch has only one leaf
216 leaf = static_cast<TLeaf *>(branch->GetListOfLeaves()->UncheckedAt(0));
217 return GetLeafTypeName(leaf, std::string(leaf->GetFullName()));
218 }
219 }
220
221 // we could not find a branch or a leaf called colName
222 return std::string();
223}
224
225/// Return a string containing the type of the given branch. Works both with real TTree branches and with temporary
226/// column created by Define. Throws if type name deduction fails.
227/// Note that for fixed- or variable-sized c-style arrays the returned type name will be RVec<T>.
228/// vector2rvec specifies whether typename 'std::vector<T>' should be converted to 'RVec<T>' or returned as is
229std::string ColumnName2ColumnTypeName(const std::string &colName, TTree *tree, RDataSource *ds, RDefineBase *define,
230 bool vector2rvec)
231{
232 std::string colType;
233
234 // must check defines first: we want Redefines to have precedence over everything else
235 if (define) {
236 colType = define->GetTypeName();
237 } else if (ds && ds->HasColumn(colName)) {
238 colType = ds->GetTypeName(colName);
239 } else if (tree) {
240 colType = GetBranchOrLeafTypeName(*tree, colName);
241 if (vector2rvec && TClassEdit::IsSTLCont(colType) == ROOT::ESTLType::kSTLvector) {
242 std::vector<std::string> split;
243 int dummy;
244 TClassEdit::GetSplit(colType.c_str(), split, dummy);
245 auto &valueType = split[1];
246 colType = ComposeRVecTypeName(valueType);
247 }
248 }
249
250 if (colType.empty())
251 throw std::runtime_error("Column \"" + colName +
252 "\" is not in a dataset and is not a custom column been defined.");
253
254 return colType;
255}
256
257/// Convert type name (e.g. "Float_t") to ROOT type code (e.g. 'F') -- see TBranch documentation.
258/// Return a space ' ' in case no match was found.
259char TypeName2ROOTTypeName(const std::string &b)
260{
261 const static std::unordered_map<std::string, char> typeName2ROOTTypeNameMap{{"char", 'B'},
262 {"Char_t", 'B'},
263 {"unsigned char", 'b'},
264 {"UChar_t", 'b'},
265 {"int", 'I'},
266 {"Int_t", 'I'},
267 {"unsigned", 'i'},
268 {"unsigned int", 'i'},
269 {"UInt_t", 'i'},
270 {"short", 'S'},
271 {"short int", 'S'},
272 {"Short_t", 'S'},
273 {"unsigned short", 's'},
274 {"unsigned short int", 's'},
275 {"UShort_t", 's'},
276 {"long", 'G'},
277 {"long int", 'G'},
278 {"Long_t", 'G'},
279 {"unsigned long", 'g'},
280 {"unsigned long int", 'g'},
281 {"ULong_t", 'g'},
282 {"double", 'D'},
283 {"Double_t", 'D'},
284 {"float", 'F'},
285 {"Float_t", 'F'},
286 {"long long", 'L'},
287 {"long long int", 'L'},
288 {"Long64_t", 'L'},
289 {"unsigned long long", 'l'},
290 {"unsigned long long int", 'l'},
291 {"ULong64_t", 'l'},
292 {"bool", 'O'},
293 {"Bool_t", 'O'}};
294
295 if (auto it = typeName2ROOTTypeNameMap.find(b); it != typeName2ROOTTypeNameMap.end())
296 return it->second;
297
298 return ' ';
299}
300
301unsigned int GetNSlots()
302{
303 unsigned int nSlots = 1;
304#ifdef R__USE_IMT
306 nSlots = ROOT::GetThreadPoolSize();
307#endif // R__USE_IMT
308 return nSlots;
309}
310
311/// Replace occurrences of '.' with '_' in each string passed as argument.
312/// An Info message is printed when this happens. Dots at the end of the string are not replaced.
313/// An exception is thrown in case the resulting set of strings would contain duplicates.
314std::vector<std::string> ReplaceDotWithUnderscore(const std::vector<std::string> &columnNames)
315{
316 auto newColNames = columnNames;
317 for (auto &col : newColNames) {
318 const auto dotPos = col.find('.');
319 if (dotPos != std::string::npos && dotPos != col.size() - 1 && dotPos != 0u) {
320 auto oldName = col;
321 std::replace(col.begin(), col.end(), '.', '_');
322 if (std::find(columnNames.begin(), columnNames.end(), col) != columnNames.end())
323 throw std::runtime_error("Column " + oldName + " would be written as " + col +
324 " but this column already exists. Please use Alias to select a new name for " +
325 oldName);
326 Info("Snapshot", "Column %s will be saved as %s", oldName.c_str(), col.c_str());
327 }
328 }
329
330 return newColNames;
331}
332
333void InterpreterDeclare(const std::string &code)
334{
335 R__LOG_DEBUG(10, RDFLogChannel()) << "Declaring the following code to cling:\n\n" << code << '\n';
336
337 if (!gInterpreter->Declare(code.c_str())) {
338 const auto msg =
339 "\nRDataFrame: An error occurred during just-in-time compilation. The lines above might indicate the cause of "
340 "the crash\n All RDF objects that have not run an event loop yet should be considered in an invalid state.\n";
341 throw std::runtime_error(msg);
342 }
343}
344
345Long64_t InterpreterCalc(const std::string &code, const std::string &context)
346{
347 R__LOG_DEBUG(10, RDFLogChannel()) << "Jitting and executing the following code:\n\n" << code << '\n';
348
349 TInterpreter::EErrorCode errorCode(TInterpreter::kNoError); // storage for cling errors
350
351 auto callCalc = [&errorCode, &context](const std::string &codeSlice) {
352 gInterpreter->Calc(codeSlice.c_str(), &errorCode);
353 if (errorCode != TInterpreter::EErrorCode::kNoError) {
354 std::string msg = "\nAn error occurred during just-in-time compilation";
355 if (!context.empty())
356 msg += " in " + context;
357 msg +=
358 ". The lines above might indicate the cause of the crash\nAll RDF objects that have not run their event "
359 "loop yet should be considered in an invalid state.\n";
360 throw std::runtime_error(msg);
361 }
362 };
363
364 // Call Calc every 1000 newlines in order to avoid jitting a very large function body, which is slow:
365 // see https://github.com/root-project/root/issues/9312 and https://github.com/root-project/root/issues/7604
366 std::size_t substr_start = 0;
367 std::size_t substr_end = 0;
368 while (substr_end != std::string::npos && substr_start != code.size() - 1) {
369 for (std::size_t i = 0u; i < 1000u && substr_end != std::string::npos; ++i) {
370 substr_end = code.find('\n', substr_end + 1);
371 }
372 const std::string subs = code.substr(substr_start, substr_end - substr_start);
373 substr_start = substr_end;
374
375 callCalc(subs);
376 }
377
378 return 0; // we used to forward the return value of Calc, but that's not possible anymore.
379}
380
381bool IsInternalColumn(std::string_view colName)
382{
383 const auto str = colName.data();
384 const auto goodPrefix = colName.size() > 3 && // has at least more characters than {r,t}df
385 ('r' == str[0] || 't' == str[0]) && // starts with r or t
386 0 == strncmp("df", str + 1, 2); // 2nd and 3rd letters are df
387 return goodPrefix && '_' == colName.back(); // also ends with '_'
388}
389
390unsigned int GetColumnWidth(const std::vector<std::string>& names, const unsigned int minColumnSpace)
391{
392 auto columnWidth = 0u;
393 for (const auto& name : names) {
394 const auto length = name.length();
395 if (length > columnWidth)
396 columnWidth = length;
397 }
398 columnWidth = (columnWidth / minColumnSpace + 1) * minColumnSpace;
399 return columnWidth;
400}
401
402void CheckReaderTypeMatches(const std::type_info &colType, const std::type_info &requestedType,
403 const std::string &colName)
404{
405 // We want to explicitly support the reading of bools as unsigned char, as
406 // this is quite common to circumvent the std::vector<bool> specialization.
407 const bool explicitlySupported = (colType == typeid(bool) && requestedType == typeid(unsigned char)) ? true : false;
408
409 // Here we compare names and not typeinfos since they may come from two different contexts: a compiled
410 // and a jitted one.
411 const auto diffTypes = (0 != std::strcmp(colType.name(), requestedType.name()));
412 auto inheritedType = [&]() {
413 auto colTClass = TClass::GetClass(colType);
414 return colTClass && colTClass->InheritsFrom(TClass::GetClass(requestedType));
415 };
416
417 if (!explicitlySupported && diffTypes && !inheritedType()) {
418 const auto tName = TypeID2TypeName(requestedType);
419 const auto colTypeName = TypeID2TypeName(colType);
420 std::string errMsg = "RDataFrame: type mismatch: column \"" + colName + "\" is being used as ";
421 if (tName.empty()) {
422 errMsg += requestedType.name();
423 errMsg += " (extracted from type info)";
424 } else {
425 errMsg += tName;
426 }
427 errMsg += " but the Define or Vary node advertises it as ";
428 if (colTypeName.empty()) {
429 auto &id = colType;
430 errMsg += id.name();
431 errMsg += " (extracted from type info)";
432 } else {
433 errMsg += colTypeName;
434 }
435 throw std::runtime_error(errMsg);
436 }
437}
438
439bool IsStrInVec(const std::string &str, const std::vector<std::string> &vec)
440{
441 return std::find(vec.cbegin(), vec.cend(), str) != vec.cend();
442}
443
444auto RStringCache::Insert(const std::string &string) -> decltype(fStrings)::const_iterator
445{
446 {
447 std::shared_lock l{fMutex};
448 if (auto it = fStrings.find(string); it != fStrings.end())
449 return it;
450 }
451
452 // TODO: Would be nicer to use a lock upgrade strategy a-la TVirtualRWMutex
453 // but that is unfortunately not usable outside the already available ROOT mutexes
454 std::unique_lock l{fMutex};
455 if (auto it = fStrings.find(string); it != fStrings.end())
456 return it;
457
458 return fStrings.insert(string).first;
459}
460} // end NS RDF
461} // end NS Internal
462} // end NS ROOT
#define R__LOG_DEBUG(DEBUGLEVEL,...)
Definition RLogger.hxx:365
#define b(i)
Definition RSha256.hxx:100
#define c(i)
Definition RSha256.hxx:101
long long Long64_t
Definition RtypesCore.h:80
unsigned long long ULong64_t
Definition RtypesCore.h:81
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition TError.cxx:218
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
char name[80]
Definition TGX11.cxx:110
#define gInterpreter
TRObject operator()(const T1 &t1) const
std::string GetTypeName() const
A log configuration for a channel, e.g.
Definition RLogger.hxx:101
auto Insert(const std::string &string) -> decltype(fStrings)::const_iterator
Inserts the input string in the cache and returns an iterator to the cached string.
Definition RDFUtils.cxx:444
RDataSource defines an API that RDataFrame can use to read arbitrary data formats.
virtual bool HasColumn(std::string_view colName) const =0
Checks if the dataset has a certain column.
virtual std::string GetTypeName(std::string_view colName) const =0
Type of a column as a string, e.g.
A Branch for the case of an object.
virtual TClass * GetClass() const
static TClass * Class()
TClassRef is used to implement a permanent reference to a TClass object.
Definition TClassRef.h:28
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:2968
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition TLeaf.h:57
virtual const char * GetTypeName() const
Definition TLeaf.h:139
virtual TLeaf * GetLeafCount() const
If this leaf stores a variable-sized array or a multi-dimensional array whose last dimension has vari...
Definition TLeaf.h:121
virtual Int_t GetLenStatic() const
Return the fixed length of this leaf.
Definition TLeaf.h:132
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
A TTree represents a columnar dataset.
Definition TTree.h:79
virtual TBranch * FindBranch(const char *name)
Return the branch that correspond to the path 'branchname', which can include the name of the tree or...
Definition TTree.cxx:4841
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
Definition TTree.cxx:5294
virtual TLeaf * GetLeaf(const char *branchname, const char *leafname)
Return pointer to the 1st Leaf named name in any Branch of this Tree or any branch in the list of fri...
Definition TTree.cxx:6195
virtual TLeaf * FindLeaf(const char *name)
Find leaf..
Definition TTree.cxx:4916
ROOT::Experimental::RLogChannel & RDFLogChannel()
Definition RDFUtils.cxx:37
std::vector< std::string > ReplaceDotWithUnderscore(const std::vector< std::string > &columnNames)
Replace occurrences of '.
Definition RDFUtils.cxx:314
const std::type_info & TypeName2TypeID(const std::string &name)
Return the type_info associated to a name.
Definition RDFUtils.cxx:62
unsigned int GetNSlots()
Definition RDFUtils.cxx:301
std::string ComposeRVecTypeName(const std::string &valueType)
Definition RDFUtils.cxx:140
std::string ColumnName2ColumnTypeName(const std::string &colName, TTree *, RDataSource *, RDefineBase *, bool vector2rvec=true)
Return a string containing the type of the given branch.
Definition RDFUtils.cxx:229
std::string GetLeafTypeName(TLeaf *leaf, const std::string &colName)
Definition RDFUtils.cxx:145
char TypeName2ROOTTypeName(const std::string &b)
Convert type name (e.g.
Definition RDFUtils.cxx:259
std::string TypeID2TypeName(const std::type_info &id)
Returns the name of a type starting from its type_info An empty string is returned in case of failure...
Definition RDFUtils.cxx:119
bool IsStrInVec(const std::string &str, const std::vector< std::string > &vec)
Definition RDFUtils.cxx:439
unsigned int GetColumnWidth(const std::vector< std::string > &names, const unsigned int minColumnSpace=8u)
Get optimal column width for printing a table given the names and the desired minimal space between c...
Definition RDFUtils.cxx:390
std::string GetBranchOrLeafTypeName(TTree &t, const std::string &colName)
Return the typename of object colName stored in t, if any.
Definition RDFUtils.cxx:172
Long64_t InterpreterCalc(const std::string &code, const std::string &context="")
Jit code in the interpreter with TInterpreter::Calc, throw in case of errors.
Definition RDFUtils.cxx:345
void CheckReaderTypeMatches(const std::type_info &colType, const std::type_info &requestedType, const std::string &colName)
Definition RDFUtils.cxx:402
bool IsInternalColumn(std::string_view colName)
Whether custom column with name colName is an "internal" column such as rdfentry_ or rdfslot_.
Definition RDFUtils.cxx:381
void InterpreterDeclare(const std::string &code)
Declare code in the interpreter via the TInterpreter::Declare method, throw in case of errors.
Definition RDFUtils.cxx:333
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Bool_t IsImplicitMTEnabled()
Returns true if the implicit multi-threading in ROOT is enabled.
Definition TROOT.cxx:570
UInt_t GetThreadPoolSize()
Returns the size of ROOT's thread pool.
Definition TROOT.cxx:577
@ kSTLvector
Definition ESTLType.h:30
ROOT::ESTLType IsSTLCont(std::string_view type)
type : type name: vector<list<classA,allocator>,allocator> result: 0 : not stl container code of cont...
int GetSplit(const char *type, std::vector< std::string > &output, int &nestedLoc, EModType mode=TClassEdit::kNone)
Stores in output (after emptying it) the split type.
TLine l
Definition textangle.C:4