Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RDFInterfaceUtils.cxx
Go to the documentation of this file.
1// Author: Enrico Guiraud, Danilo Piparo CERN 02/2018
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 <ROOT/RDataSource.hxx>
12#include <ROOT/RTTreeDS.hxx>
15#include <ROOT/RDF/RDisplay.hxx>
22#include <ROOT/RDF/Utils.hxx>
23#include <string_view>
24#include <TBranch.h>
25#include <TClass.h>
26#include <TClassEdit.h>
27#include <TDataType.h>
28#include <TError.h>
29#include <TLeaf.h>
30#include <TObjArray.h>
31#include <TPRegexp.h>
32#include <TROOT.h>
33#include <TString.h>
34#include <TTree.h>
35#include <TVirtualMutex.h>
36
37// pragma to disable warnings on Rcpp which have
38// so many noise compiling
39#if defined(__GNUC__)
40#pragma GCC diagnostic push
41#pragma GCC diagnostic ignored "-Woverloaded-virtual"
42#pragma GCC diagnostic ignored "-Wshadow"
43#endif
44#include "lexertk.hpp"
45#if defined(__GNUC__)
46#pragma GCC diagnostic pop
47#endif
48
49#include <algorithm>
50#include <cassert>
51#include <cstdlib> // for size_t
52#include <iterator> // for back_insert_iterator
53#include <map>
54#include <memory>
55#include <set>
56#include <sstream>
57#include <stdexcept>
58#include <string>
59#include <type_traits> // for remove_reference<>::type
60#include <typeinfo>
61#include <unordered_map>
62#include <unordered_set>
63#include <utility> // for pair
64#include <vector>
65
66namespace ROOT {
67namespace Detail {
68namespace RDF {
69class RDefineBase;
70} // namespace RDF
71namespace Internal {
72namespace RDF {
73class RJittedAction;
74}
75} // namespace Internal
76} // namespace Detail
77
78} // namespace ROOT
79
80namespace {
83
84/// A string expression such as those passed to Filter and Define, digested to a standardized form
85struct ParsedExpression {
86 /// The string expression with the dummy variable names in fVarNames in place of the original column names
87 std::string fExpr;
88 /// The list of valid column names that were used in the original string expression.
89 /// Duplicates are removed and column aliases (created with Alias calls) are resolved.
90 ColumnNames_t fUsedCols;
91 /// The list of variable names used in fExpr, with same ordering and size as fUsedCols
92 ColumnNames_t fVarNames;
93};
94
95/// Look at expression `expr` and return a pair of (column names used, aliases used)
96std::pair<ColumnNames_t, ColumnNames_t>
97FindUsedColsAndAliases(const std::string &expr, const ColumnNames_t &treeBranchNames,
99{
100 lexertk::generator tokens;
101 const auto tokensOk = tokens.process(expr);
102 if (!tokensOk) {
103 const auto msg = "Failed to tokenize expression:\n" + expr + "\n\nMake sure it is valid C++.";
104 throw std::runtime_error(msg);
105 }
106
107 std::unordered_set<std::string> usedCols;
108 std::unordered_set<std::string> usedAliases;
109
110 // iterate over tokens in expression and fill usedCols and usedAliases
111 const auto nTokens = tokens.size();
112 const auto kSymbol = lexertk::token::e_symbol;
113 for (auto i = 0u; i < nTokens; ++i) {
114 const auto &tok = tokens[i];
115 // lexertk classifies '&' as e_symbol for some reason
116 if (tok.type != kSymbol || tok.value == "&" || tok.value == "|") {
117 // token is not a potential variable name, skip it
118 continue;
119 }
120
121 ColumnNames_t potentialColNames({tok.value});
122
123 // if token is the start of a dot chain (a.b.c...), a.b, a.b.c etc. are also potential column names
124 auto dotChainKeepsGoing = [&](unsigned int _i) {
125 return _i + 2 <= nTokens && tokens[_i + 1].value == "." && tokens[_i + 2].type == kSymbol;
126 };
127 while (dotChainKeepsGoing(i)) {
128 potentialColNames.emplace_back(potentialColNames.back() + "." + tokens[i + 2].value);
129 i += 2; // consume the tokens we looked at
130 }
131
132 // in an expression such as `a.b`, if `a` is a column alias add it to `usedAliases` and
133 // replace the alias with the real column name in `potentialColNames`.
134 const auto maybeAnAlias = potentialColNames[0]; // intentionally a copy as we'll modify potentialColNames later
135 const auto &resolvedAlias = colRegister.ResolveAlias(maybeAnAlias);
136 if (resolvedAlias != maybeAnAlias) { // this is an alias
138 for (auto &s : potentialColNames)
139 s.replace(0, maybeAnAlias.size(), resolvedAlias);
140 }
141
142 // find the longest potential column name that is an actual column name
143 // (potential columns are sorted by length, so we search from the end to find the longest)
144 auto isRDFColumn = [&](const std::string &col) {
145 if (colRegister.IsDefineOrAlias(col) || IsStrInVec(col, treeBranchNames) ||
147 return true;
148 return false;
149 };
150 const auto longestRDFColMatch = std::find_if(potentialColNames.crbegin(), potentialColNames.crend(), isRDFColumn);
153 }
154
155 return {{usedCols.begin(), usedCols.end()}, {usedAliases.begin(), usedAliases.end()}};
156}
157
158/// Substitute each '.' in a string with '\.'
159std::string EscapeDots(const std::string &s)
160{
161 out(s);
162 TPRegexp dot("\\.");
163 dot.Substitute(out, "\\.", "g");
164 return std::string(std::move(out));
165}
166
167TString ResolveAliases(const TString &expr, const ColumnNames_t &usedAliases,
169{
170 expr);
171
172 for (const auto &alias : usedAliases) {
173 const auto &col = colRegister.ResolveAlias(alias);
174 TPRegexp replacer("\\b" + EscapeDots(alias) + "\\b");
175 replacer.Substitute(out, col.data(), "g");
176 }
177
178 return out;
179}
180
181ParsedExpression ParseRDFExpression(std::string_view expr, const ColumnNames_t &treeBranchNames,
183 const ColumnNames_t &dataSourceColNames)
184{
185 // transform `#var` into `R_rdf_sizeof_var`
187 // regex explanation:
188 // #
189 // - matches the literal character #
190 // (?!(ifdef|ifndef|if|else|elif|endif|pragma|define|undef|include|line))
191 // - negative lookahead (i.e. don't match these occurrences) to exclude preprocessor directives e.g. #ifdef
192 // ([a-zA-Z_][a-zA-Z0-9_]*)
193 // - match characters that make up the variable name after the #
194 // (?=(?:[^"]*"[^"]*")*[^"]*$)
195 // - positive lookahead (i.e. match these occurrences) checking that there is always an even number of quotes
196 // *after* the matched character sequence, using the non-capturing group (?:[^"]*"[^"]*"). We leverage the
197 // fact that for any character sequence to be within quotes there must be an odd number of quotes after the
198 // sequence and before the end of the line.
200 R"REGEX(#(?!(ifdef|ifndef|if|else|elif|endif|pragma|define|undef|include|line))([a-zA-Z_][a-zA-Z0-9_]*)(?=(?:[^"]*"[^"]*")*[^"]*$))REGEX");
201 colSizeReplacer.Substitute(preProcessedExpr, "R_rdf_sizeof_$2", "g");
202
203 ColumnNames_t usedCols;
204 ColumnNames_t usedAliases;
205 std::tie(usedCols, usedAliases) =
207
209
210 // when we are done, exprWithVars willl be the same as preProcessedExpr but column names will be substituted with
211 // the dummy variable names in varNames
213
214 ColumnNames_t varNames(usedCols.size());
215 for (auto i = 0u; i < varNames.size(); ++i)
216 varNames[i] = "var" + std::to_string(i);
217
218 // sort the vector usedColsAndAliases by decreasing length of its elements,
219 // so in case of friends we guarantee we never substitute a column name with another column containing it
220 // ex. without sorting when passing "x" and "fr.x", the replacer would output "var0" and "fr.var0",
221 // because it has already substituted "x", hence the "x" in "fr.x" would be recognized as "var0",
222 // whereas the desired behaviour is handling them as "var0" and "var1"
223 std::sort(usedCols.begin(), usedCols.end(),
224 [](const std::string &a, const std::string &b) { return a.size() > b.size(); });
225 for (const auto &col : usedCols) {
226 const auto varIdx = std::distance(usedCols.begin(), std::find(usedCols.begin(), usedCols.end(), col));
227 TPRegexp replacer("\\b" + EscapeDots(col) + "\\b");
228 replacer.Substitute(exprWithVars, varNames[varIdx], "g");
229 }
230
231 return ParsedExpression{std::string(std::move(exprWithVars)), std::move(usedCols), std::move(varNames)};
232}
233
234/// Return the static global map of Filter/Define functions that have been jitted.
235/// It's used to check whether a given expression has already been jitted, and
236/// to look up its associated variable name if it is.
237/// Keys in the map are the body of the expression, values are the name of the
238/// jitted variable that corresponds to that expression. For example, for:
239/// auto f1(){ return 42; }
240/// key would be "(){ return 42; }" and value would be "f1".
241std::unordered_map<std::string, std::string> &GetJittedExprs() {
242 static std::unordered_map<std::string, std::string> jittedExpressions;
243 return jittedExpressions;
244}
245
246std::string
247BuildFunctionString(const std::string &expr, const ColumnNames_t &vars, const ColumnNames_t &varTypes)
248{
249 assert(vars.size() == varTypes.size());
250
251 TPRegexp re(R"(\breturn\b)");
252 const bool hasReturnStmt = re.MatchB(expr);
253
254 static const std::vector<std::string> fundamentalTypes = {
255 "int",
256 "signed",
257 "signed int",
258 "Int_t",
259 "unsigned",
260 "unsigned int",
261 "UInt_t",
262 "double",
263 "Double_t",
264 "float",
265 "Float_t",
266 "char",
267 "Char_t",
268 "unsigned char",
269 "UChar_t",
270 "bool",
271 "Bool_t",
272 "short",
273 "short int",
274 "Short_t",
275 "long",
276 "long int",
277 "long long int",
278 "Long64_t",
279 "unsigned long",
280 "unsigned long int",
281 "ULong64_t",
282 "std::size_t",
283 "size_t",
284 "Ssiz_t"
285 };
286
287 std::stringstream ss;
288 ss << "(";
289 for (auto i = 0u; i < vars.size(); ++i) {
290 std::string fullType;
291 const auto &type = varTypes[i];
293 // pass it by const value to help detect common mistakes such as if(x = 3)
294 fullType = "const " + type + " ";
295 } else {
296 // We pass by reference to avoid expensive copies
297 // It can't be const reference in general, as users might want/need to call non-const methods on the values
298 fullType = type + "& ";
299 }
300 ss << fullType << vars[i] << ", ";
301 }
302 if (!vars.empty())
303 ss.seekp(-2, ss.cur);
304
305 if (hasReturnStmt)
306 ss << "){";
307 else
308 ss << "){return ";
309 ss << expr << "\n;}";
310
311 return ss.str();
312}
313
314/// Declare a function to the interpreter in namespace R_rdf, return the name of the jitted function.
315/// If the function is already in GetJittedExprs, return the name for the function that has already been jitted.
316std::string DeclareFunction(const std::string &expr, const ColumnNames_t &vars, const ColumnNames_t &varTypes)
317{
319
320 const auto funcCode = BuildFunctionString(expr, vars, varTypes);
321 auto &exprMap = GetJittedExprs();
322 const auto exprIt = exprMap.find(funcCode);
323 if (exprIt != exprMap.end()) {
324 // expression already there
325 const auto funcName = exprIt->second;
326 return funcName;
327 }
328
329 // new expression
330 const auto funcBaseName = "func" + std::to_string(exprMap.size());
331 const auto funcFullName = "R_rdf::" + funcBaseName;
332
333 const auto toDeclare = "namespace R_rdf {\nauto " + funcBaseName + funcCode + "\nusing " + funcBaseName +
334 "_ret_t = typename ROOT::TypeTraits::CallableTraits<decltype(" + funcBaseName +
335 ")>::ret_type;\n}";
337
338 // InterpreterDeclare could throw. If it doesn't, mark the function as already jitted
339 exprMap.insert({funcCode, funcFullName});
340
341 return funcFullName;
342}
343
344/// Each jitted function comes with a func_ret_t type alias for its return type.
345/// Resolve that alias and return the true type as string.
346std::string RetTypeOfFunc(const std::string &funcName)
347{
348 const auto dt = gROOT->GetType((funcName + "_ret_t").c_str());
349 R__ASSERT(dt != nullptr);
350 const auto type = dt->GetFullTypeName();
351 return type;
352}
353
354[[noreturn]] void
355ThrowJitBuildActionHelperTypeError(const std::string &actionTypeNameBase, const std::type_info &helperArgType)
356{
357 int err = 0;
359 std::string actionHelperTypeName = cname;
360 delete[] cname;
361 if (err != 0)
363
364 std::string exceptionText =
365 "RDataFrame::Jit: cannot just-in-time compile a \"" + actionTypeNameBase + "\" action using helper type \"" +
367 "\". This typically happens in a custom `Fill` or `Book` invocation where the types of the input columns have "
368 "not been specified as template parameters and the ROOT interpreter has no knowledge of this type of action "
369 "helper. Please add template parameters for the types of the input columns to avoid jitting this action (i.e. "
370 "`df.Fill<float>(..., {\"x\"})`, where `float` is the type of `x`) or declare the action helper type to the "
371 "interpreter, e.g. via gInterpreter->Declare.";
372
373 throw std::runtime_error(exceptionText);
374}
375
376} // anonymous namespace
377
378namespace ROOT {
379namespace Internal {
380namespace RDF {
381
382/// Take a list of column names, return that list with entries starting by '#' filtered out.
383/// The function throws when filtering out a column this way.
384ColumnNames_t FilterArraySizeColNames(const ColumnNames_t &columnNames, const std::string &action)
385{
386 ColumnNames_t columnListWithoutSizeColumns;
387 ColumnNames_t filteredColumns;
388 std::copy_if(columnNames.begin(), columnNames.end(), std::back_inserter(columnListWithoutSizeColumns),
389 [&](const std::string &name) {
390 if (name[0] == '#') {
391 filteredColumns.emplace_back(name);
392 return false;
393 } else {
394 return true;
395 }
396 });
397
398 if (!filteredColumns.empty()) {
399 std::string msg = "Column name(s) {";
400 for (auto &c : filteredColumns)
401 msg += c + ", ";
402 msg[msg.size() - 2] = '}';
403 msg += "will be ignored. Please go through a valid Alias to " + action + " an array size column";
404 throw std::runtime_error(msg);
405 }
406
408}
409
410std::string ResolveAlias(const std::string &col, const std::map<std::string, std::string> &aliasMap)
411{
412 const auto it = aliasMap.find(col);
413 if (it != aliasMap.end())
414 return it->second;
415
416 // #var is an alias for R_rdf_sizeof_var
417 if (col.size() > 1 && col[0] == '#')
418 return "R_rdf_sizeof_" + col.substr(1);
419
420 return col;
421}
422
423void CheckValidCppVarName(std::string_view var, const std::string &where)
424{
425 bool isValid = true;
426
427 if (var.empty())
428 isValid = false;
429 const char firstChar = var[0];
430
431 // first character must be either a letter or an underscore
432 auto isALetter = [](char c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); };
433 const bool isValidFirstChar = firstChar == '_' || isALetter(firstChar);
434 if (!isValidFirstChar)
435 isValid = false;
436
437 // all characters must be either a letter, an underscore or a number
438 auto isANumber = [](char c) { return c >= '0' && c <= '9'; };
439 auto isValidTok = [&isALetter, &isANumber](char c) { return c == '_' || isALetter(c) || isANumber(c); };
440 for (const char c : var)
441 if (!isValidTok(c))
442 isValid = false;
443
444 if (!isValid) {
445 const auto objName = where == "Define" ? "column" : "variation";
446 const auto error = "RDataFrame::" + where + ": cannot define " + objName + " \"" + std::string(var) +
447 "\". Not a valid C++ variable name.";
448 throw std::runtime_error(error);
449 }
450}
451
452std::string DemangleTypeIdName(const std::type_info &typeInfo)
453{
454 int dummy(0);
456 std::string tname(tn);
457 free(tn);
458 return tname;
459}
460
461ColumnNames_t
462ConvertRegexToColumns(const ColumnNames_t &colNames, std::string_view columnNameRegexp, std::string_view callerName)
463{
464 const auto theRegexSize = columnNameRegexp.size();
465 std::string theRegex(columnNameRegexp);
466
467 const auto isEmptyRegex = 0 == theRegexSize;
468 // This is to avoid cases where branches called b1, b2, b3 are all matched by expression "b"
469 if (theRegexSize > 0 && theRegex[0] != '^')
470 theRegex = "^" + theRegex;
471 if (theRegexSize > 0 && theRegex[theRegexSize - 1] != '$')
472 theRegex = theRegex + "$";
473
474 ColumnNames_t selectedColumns;
475
476 // Since we support gcc48 and it does not provide in its stl std::regex,
477 // we need to use TPRegexp
478 TPRegexp regexp(theRegex);
479 for (auto &&colName : colNames) {
480 if ((isEmptyRegex || regexp.MatchB(colName.c_str())) && !IsInternalColumn(colName)) {
481 selectedColumns.emplace_back(colName);
482 }
483 }
484
485 if (selectedColumns.empty()) {
486 std::string text(callerName);
487 if (columnNameRegexp.empty()) {
488 text = ": there is no column available to match.";
489 } else {
490 text = ": regex \"" + std::string(columnNameRegexp) + "\" did not match any column.";
491 }
492 throw std::runtime_error(text);
493 }
494 return selectedColumns;
495}
496
497/// Throw if column `definedColView` is already there.
498void CheckForRedefinition(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister,
499 const ColumnNames_t &treeColumns, const ColumnNames_t &dataSourceColumns)
500{
501
502 std::string error{};
503 if (colRegister.IsAlias(definedColView))
504 error = "An alias with that name, pointing to column \"" + std::string(colRegister.ResolveAlias(definedColView)) +
505 "\", already exists in this branch of the computation graph.";
506 else if (colRegister.IsDefineOrAlias(definedColView))
507 error = "A column with that name has already been Define'd. Use Redefine to force redefinition.";
508 // else, check if definedColView is in the list of tree branches. This is a bit better than interrogating the TTree
509 // directly because correct usage of GetBranch, FindBranch, GetLeaf and FindLeaf can be tricky; so let's assume we
510 // got it right when we collected the list of available branches.
511 else if (std::find(treeColumns.begin(), treeColumns.end(), definedColView) != treeColumns.end())
512 error =
513 "A branch with that name is already present in the input TTree/TChain. Use Redefine to force redefinition.";
515 error =
516 "A column with that name is already present in the input data source. Use Redefine to force redefinition.";
517
518 if (!error.empty()) {
519 error = "RDataFrame::" + where + ": cannot define column \"" + std::string(definedColView) + "\". " + error;
520 throw std::runtime_error(error);
521 }
522}
523
524/// Throw if column `definedColView` is _not_ already there.
525void CheckForDefinition(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister,
526 const ColumnNames_t &treeColumns, const ColumnNames_t &dataSourceColumns)
527{
528 std::string error{};
529
530 if (colRegister.IsAlias(definedColView)) {
531 error = "An alias with that name, pointing to column \"" + std::string(colRegister.ResolveAlias(definedColView)) +
532 "\", already exists. Aliases cannot be Redefined or Varied.";
533 }
534
535 if (error.empty()) {
536 const bool isAlreadyDefined = colRegister.IsDefineOrAlias(definedColView);
537 // check if definedCol is in the list of tree branches. This is a bit better than interrogating the TTree
538 // directly because correct usage of GetBranch, FindBranch, GetLeaf and FindLeaf can be tricky; so let's assume we
539 // got it right when we collected the list of available branches.
540 const bool isABranch = std::find(treeColumns.begin(), treeColumns.end(), definedColView) != treeColumns.end();
541 const bool isADSColumn =
543
545 error = "No column with that name was found in the dataset. Use Define to create a new column.";
546 }
547
548 if (!error.empty()) {
549 if (where == "DefaultValueFor")
550 error = "RDataFrame::" + where + ": cannot provide default values for column \"" +
551 std::string(definedColView) + "\". " + error;
552 else
553 error = "RDataFrame::" + where + ": cannot redefine or vary column \"" + std::string(definedColView) + "\". " +
554 error;
555 throw std::runtime_error(error);
556 }
557}
558
559/// Throw if the column has systematic variations attached.
560void CheckForNoVariations(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister)
561{
562 const std::string definedCol(definedColView);
563 const auto &variationDeps = colRegister.GetVariationDeps(definedCol);
564 if (!variationDeps.empty()) {
565 if (where == "Redefine") {
566 const std::string error = "RDataFrame::" + where + ": cannot redefine column \"" + definedCol +
567 "\". The column depends on one or more systematic variations and re-defining varied "
568 "columns is not supported.";
569 throw std::runtime_error(error);
570 } else if (where == "DefaultValueFor") {
571 const std::string error = "RDataFrame::" + where + ": cannot provide a default value for column \"" +
572 definedCol +
573 "\". The column depends on one or more systematic variations and it should not be "
574 "possible to have missing values in varied columns.";
575 throw std::runtime_error(error);
576 } else {
577 const std::string error =
578 "RDataFrame::" + where + ": this operation cannot work with columns that depend on systematic variations.";
579 throw std::runtime_error(error);
580 }
581 }
582}
583
584void CheckTypesAndPars(unsigned int nTemplateParams, unsigned int nColumnNames)
585{
587 std::string err_msg = "The number of template parameters specified is ";
588 err_msg += std::to_string(nTemplateParams);
589 err_msg += " while ";
590 err_msg += std::to_string(nColumnNames);
591 err_msg += " columns have been specified.";
592 throw std::runtime_error(err_msg);
593 }
594}
595
596/// Choose between local column names or default column names, throw in case of errors.
597const ColumnNames_t
598SelectColumns(unsigned int nRequiredNames, const ColumnNames_t &names, const ColumnNames_t &defaultNames)
599{
600 if (names.empty()) {
601 // use default column names
602 if (defaultNames.size() < nRequiredNames)
603 throw std::runtime_error(
604 std::to_string(nRequiredNames) + " column name" + (nRequiredNames == 1 ? " is" : "s are") +
605 " required but none were provided and the default list has size " + std::to_string(defaultNames.size()));
606 // return first nRequiredNames default column names
607 return ColumnNames_t(defaultNames.begin(), defaultNames.begin() + nRequiredNames);
608 } else {
609 // use column names provided by the user to this particular transformation/action
610 if (names.size() != nRequiredNames) {
611 auto msg = std::to_string(nRequiredNames) + " column name" + (nRequiredNames == 1 ? " is" : "s are") +
612 " required but " + std::to_string(names.size()) + (names.size() == 1 ? " was" : " were") +
613 " provided:";
614 for (const auto &name : names)
615 msg += " \"" + name + "\",";
616 msg.back() = '.';
617 throw std::runtime_error(msg);
618 }
619 return names;
620 }
621}
622
623ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, const ColumnNames_t &datasetColumns,
624 const RColumnRegister &definedCols, const ColumnNames_t &dataSourceColumns)
625{
626 ColumnNames_t unknownColumns;
627 for (auto &column : requiredCols) {
628 const auto isBranch = std::find(datasetColumns.begin(), datasetColumns.end(), column) != datasetColumns.end();
629 if (isBranch)
630 continue;
631 if (definedCols.IsDefineOrAlias(column))
632 continue;
633 const auto isDataSourceColumn =
636 continue;
637 unknownColumns.emplace_back(column);
638 }
639 return unknownColumns;
640}
641
642std::vector<std::string> GetFilterNames(const std::shared_ptr<RLoopManager> &loopManager)
643{
644 return loopManager->GetFiltersNames();
645}
646
648{
649 // split name into directory and treename if needed
650 std::string_view dirName = "";
651 std::string_view treeName = fullTreeName;
652 const auto lastSlash = fullTreeName.rfind('/');
653 if (std::string_view::npos != lastSlash) {
654 dirName = treeName.substr(0, lastSlash);
655 treeName = treeName.substr(lastSlash + 1, treeName.size());
656 }
657 return {std::string(treeName), std::string(dirName)};
658}
659
660std::string PrettyPrintAddr(const void *const addr)
661{
662 std::stringstream s;
663 // Windows-friendly
665 return s.str();
666}
667
668/// Book the jitting of a Filter call
669std::shared_ptr<RDFDetail::RJittedFilter>
670BookFilterJit(std::shared_ptr<RDFDetail::RNodeBase> *prevNodeOnHeap, std::string_view name, std::string_view expression,
671 const ColumnNames_t &branches, const RColumnRegister &colRegister, TTree *tree, RDataSource *ds)
672{
673 const auto &dsColumns = ds ? ds->GetColumnNames() : ColumnNames_t{};
674
675 const auto parsedExpr = ParseRDFExpression(expression, branches, colRegister, dsColumns);
676 const auto exprVarTypes =
677 GetValidatedArgTypes(parsedExpr.fUsedCols, colRegister, tree, ds, "Filter", /*vector2RVec=*/true);
678 const auto funcName = DeclareFunction(parsedExpr.fExpr, parsedExpr.fVarNames, exprVarTypes);
679 const auto type = RetTypeOfFunc(funcName);
680 if (type != "bool")
681 std::runtime_error("Filter: the following expression does not evaluate to bool:\n" + std::string(expression));
682
683 // definesOnHeap is deleted by the jitted call to JitFilterHelper
687
688 const auto jittedFilter = std::make_shared<RDFDetail::RJittedFilter>(
689 (*prevNodeOnHeap)->GetLoopManagerUnchecked(), name,
690 Union(colRegister.GetVariationDeps(parsedExpr.fUsedCols), (*prevNodeOnHeap)->GetVariations()));
691
692 // Produce code snippet that creates the filter and registers it with the corresponding RJittedFilter
693 // Windows requires std::hex << std::showbase << (size_t)pointer to produce notation "0x1234"
694 std::stringstream filterInvocation;
695 filterInvocation << "ROOT::Internal::RDF::JitFilterHelper(" << funcName << ", new const char*["
696 << parsedExpr.fUsedCols.size() << "]{";
697 for (const auto &col : parsedExpr.fUsedCols)
698 filterInvocation << "\"" << col << "\", ";
699 if (!parsedExpr.fUsedCols.empty())
700 filterInvocation.seekp(-2, filterInvocation.cur); // remove the last ",
701 // lifetime of pointees:
702 // - jittedFilter: heap-allocated weak_ptr to the actual jittedFilter that will be deleted by JitFilterHelper
703 // - prevNodeOnHeap: heap-allocated shared_ptr to the actual previous node that will be deleted by JitFilterHelper
704 // - definesOnHeap: heap-allocated, will be deleted by JitFilterHelper
705 filterInvocation << "}, " << parsedExpr.fUsedCols.size() << ", \"" << name << "\", "
706 << "reinterpret_cast<std::weak_ptr<ROOT::Detail::RDF::RJittedFilter>*>("
708 << "reinterpret_cast<std::shared_ptr<ROOT::Detail::RDF::RNodeBase>*>(" << prevNodeAddr << "),"
709 << "reinterpret_cast<ROOT::Internal::RDF::RColumnRegister*>(" << definesOnHeapAddr << ")"
710 << ");\n";
711
712 auto lm = jittedFilter->GetLoopManagerUnchecked();
713 lm->ToJitExec(filterInvocation.str());
714
715 return jittedFilter;
716}
717
718/// Book the jitting of a Define call
719std::shared_ptr<RJittedDefine> BookDefineJit(std::string_view name, std::string_view expression, RLoopManager &lm,
720 RDataSource *ds, const RColumnRegister &colRegister,
721 const ColumnNames_t &branches,
722 std::shared_ptr<RNodeBase> *upcastNodeOnHeap)
723{
724 auto *const lm.GetTree();
725 const auto &dsColumns = ds ? ds->GetColumnNames() : ColumnNames_t{};
726
727 const auto parsedExpr = ParseRDFExpression(expression, branches, colRegister, dsColumns);
728 const auto exprVarTypes =
729 GetValidatedArgTypes(parsedExpr.fUsedCols, colRegister, tree, ds, "Define", /*vector2RVec=*/true);
730 const auto funcName = DeclareFunction(parsedExpr.fExpr, parsedExpr.fVarNames, exprVarTypes);
731 const auto type = RetTypeOfFunc(funcName);
732
733 auto definesCopy = new RColumnRegister(colRegister);
735 auto jittedDefine = std::make_shared<RDFDetail::RJittedDefine>(name, type, lm, colRegister, parsedExpr.fUsedCols);
736
737 std::stringstream defineInvocation;
738 defineInvocation << "ROOT::Internal::RDF::JitDefineHelper<ROOT::Internal::RDF::DefineTypes::RDefineTag>(" << funcName
739 << ", new const char*[" << parsedExpr.fUsedCols.size() << "]{";
740 for (const auto &col : parsedExpr.fUsedCols) {
741 defineInvocation << "\"" << col << "\", ";
742 }
743 if (!parsedExpr.fUsedCols.empty())
744 defineInvocation.seekp(-2, defineInvocation.cur); // remove the last ",
745 // lifetime of pointees:
746 // - lm is the loop manager, and if that goes out of scope jitting does not happen at all (i.e. will always be valid)
747 // - jittedDefine: heap-allocated weak_ptr that will be deleted by JitDefineHelper after usage
748 // - definesAddr: heap-allocated, will be deleted by JitDefineHelper after usage
749 defineInvocation << "}, " << parsedExpr.fUsedCols.size() << ", \"" << name
750 << "\", reinterpret_cast<ROOT::Detail::RDF::RLoopManager*>(" << PrettyPrintAddr(&lm)
751 << "), reinterpret_cast<std::weak_ptr<ROOT::Detail::RDF::RJittedDefine>*>("
753 << "), reinterpret_cast<ROOT::Internal::RDF::RColumnRegister*>(" << definesAddr
754 << "), reinterpret_cast<std::shared_ptr<ROOT::Detail::RDF::RNodeBase>*>("
755 << PrettyPrintAddr(upcastNodeOnHeap) << "));\n";
756
757 lm.ToJitExec(defineInvocation.str());
758 return jittedDefine;
759}
760
761/// Book the jitting of a DefinePerSample call
762std::shared_ptr<RJittedDefine> BookDefinePerSampleJit(std::string_view name, std::string_view expression,
763 RLoopManager &lm, const RColumnRegister &colRegister,
764 std::shared_ptr<RNodeBase> *upcastNodeOnHeap)
765{
766 const auto funcName = DeclareFunction(std::string(expression), {"rdfslot_", "rdfsampleinfo_"},
767 {"unsigned int", "const ROOT::RDF::RSampleInfo"});
768 const auto retType = RetTypeOfFunc(funcName);
769
770 auto definesCopy = new RColumnRegister(colRegister);
772 auto jittedDefine = std::make_shared<RDFDetail::RJittedDefine>(name, retType, lm, colRegister, ColumnNames_t{});
773
774 std::stringstream defineInvocation;
775 defineInvocation << "ROOT::Internal::RDF::JitDefineHelper<ROOT::Internal::RDF::DefineTypes::RDefinePerSampleTag>("
776 << funcName << ", nullptr, 0, ";
777 // lifetime of pointees:
778 // - lm is the loop manager, and if that goes out of scope jitting does not happen at all (i.e. will always be valid)
779 // - jittedDefine: heap-allocated weak_ptr that will be deleted by JitDefineHelper after usage
780 // - definesAddr: heap-allocated, will be deleted by JitDefineHelper after usage
781 defineInvocation << "\"" << name << "\", reinterpret_cast<ROOT::Detail::RDF::RLoopManager*>(" << PrettyPrintAddr(&lm)
782 << "), reinterpret_cast<std::weak_ptr<ROOT::Detail::RDF::RJittedDefine>*>("
784 << "), reinterpret_cast<ROOT::Internal::RDF::RColumnRegister*>(" << definesAddr
785 << "), reinterpret_cast<std::shared_ptr<ROOT::Detail::RDF::RNodeBase>*>("
786 << PrettyPrintAddr(upcastNodeOnHeap) << "));\n";
787
788 lm.ToJitExec(defineInvocation.str());
789 return jittedDefine;
790}
791
792/// Book the jitting of a Vary call
793std::shared_ptr<RJittedVariation>
794BookVariationJit(const std::vector<std::string> &colNames, std::string_view variationName,
795 const std::vector<std::string> &variationTags, std::string_view expression, RLoopManager &lm,
796 RDataSource *ds, const RColumnRegister &colRegister, const ColumnNames_t &branches,
797 std::shared_ptr<RNodeBase> *upcastNodeOnHeap, bool isSingleColumn)
798{
799 auto *const lm.GetTree();
800 const auto &dsColumns = ds ? ds->GetColumnNames() : ColumnNames_t{};
801
802 const auto parsedExpr = ParseRDFExpression(expression, branches, colRegister, dsColumns);
803 const auto exprVarTypes =
804 GetValidatedArgTypes(parsedExpr.fUsedCols, colRegister, tree, ds, "Vary", /*vector2RVec=*/true);
805 const auto funcName = DeclareFunction(parsedExpr.fExpr, parsedExpr.fVarNames, exprVarTypes);
806 const auto type = RetTypeOfFunc(funcName);
807
808 if (type.rfind("ROOT::VecOps::RVec", 0) != 0) {
809 // Avoid leak
810 delete upcastNodeOnHeap;
811 upcastNodeOnHeap = nullptr;
812 throw std::runtime_error(
813 "Jitted Vary expressions must return an RVec object. The following expression returns a " + type +
814 " instead:\n" + parsedExpr.fExpr);
815 }
816
817 auto colRegisterCopy = new RColumnRegister(colRegister);
819 auto jittedVariation = std::make_shared<RJittedVariation>(colNames, variationName, variationTags, type, colRegister,
820 lm, parsedExpr.fUsedCols);
821
822 // build invocation to JitVariationHelper
823 // arrays of strings are passed as const char** plus size.
824 // lifetime of pointees:
825 // - lm is the loop manager, and if that goes out of scope jitting does not happen at all (i.e. will always be valid)
826 // - jittedVariation: heap-allocated weak_ptr that will be deleted by JitDefineHelper after usage
827 // - definesAddr: heap-allocated, will be deleted by JitDefineHelper after usage
828 std::stringstream varyInvocation;
829 varyInvocation << "ROOT::Internal::RDF::JitVariationHelper<" << (isSingleColumn ? "true" : "false") << ">("
830 << funcName << ", new const char*[" << parsedExpr.fUsedCols.size() << "]{";
831 for (const auto &col : parsedExpr.fUsedCols) {
832 varyInvocation << "\"" << col << "\", ";
833 }
834 if (!parsedExpr.fUsedCols.empty())
835 varyInvocation.seekp(-2, varyInvocation.cur); // remove the last ", "
836 varyInvocation << "}, " << parsedExpr.fUsedCols.size();
837 varyInvocation << ", new const char*[" << colNames.size() << "]{";
838 for (const auto &col : colNames) {
839 varyInvocation << "\"" << col << "\", ";
840 }
841 varyInvocation.seekp(-2, varyInvocation.cur); // remove the last ", "
842 varyInvocation << "}, " << colNames.size() << ", new const char*[" << variationTags.size() << "]{";
843 for (const auto &tag : variationTags) {
844 varyInvocation << "\"" << tag << "\", ";
845 }
846 varyInvocation.seekp(-2, varyInvocation.cur); // remove the last ", "
847 varyInvocation << "}, " << variationTags.size() << ", \"" << variationName
848 << "\", reinterpret_cast<ROOT::Detail::RDF::RLoopManager*>(" << PrettyPrintAddr(&lm)
849 << "), reinterpret_cast<std::weak_ptr<ROOT::Internal::RDF::RJittedVariation>*>("
851 << "), reinterpret_cast<ROOT::Internal::RDF::RColumnRegister*>(" << colRegisterAddr
852 << "), reinterpret_cast<std::shared_ptr<ROOT::Detail::RDF::RNodeBase>*>("
853 << PrettyPrintAddr(upcastNodeOnHeap) << "));\n";
854
855 lm.ToJitExec(varyInvocation.str());
856 return jittedVariation;
857}
858
859// Jit and call something equivalent to "this->BuildAndBook<ColTypes...>(params...)"
860// (see comments in the body for actual jitted code)
861std::string JitBuildAction(const ColumnNames_t &cols, std::shared_ptr<RDFDetail::RNodeBase> *prevNode,
862 const std::type_info &helperArgType, const std::type_info &at, void *helperArgOnHeap,
863 TTree *tree, const unsigned int nSlots, const RColumnRegister &colRegister, RDataSource *ds,
864 std::weak_ptr<RJittedAction> *jittedActionOnHeap, const bool vector2RVec)
865{
866 // retrieve type of action as a string
868 if (!actionTypeClass) {
869 std::string exceptionText = "An error occurred while inferring the action type of the operation.";
870 throw std::runtime_error(exceptionText);
871 }
872 const std::string actionTypeName = actionTypeClass->GetName();
873 const std::string actionTypeNameBase = actionTypeName.substr(actionTypeName.rfind(':') + 1);
874
875 // retrieve type of result of the action as a string
877 if (helperArgTypeName.empty()) {
879 }
880
881 auto definesCopy = new RColumnRegister(colRegister); // deleted in jitted CallBuildAction
883
884 // Build a call to CallBuildAction with the appropriate argument. When run through the interpreter, this code will
885 // just-in-time create an RAction object and it will assign it to its corresponding RJittedAction.
886 std::stringstream createAction_str;
887 createAction_str << "ROOT::Internal::RDF::CallBuildAction<" << actionTypeName;
889 for (auto &colType : columnTypeNames)
890 createAction_str << ", " << colType;
891 // on Windows, to prefix the hexadecimal value of a pointer with '0x',
892 // one need to write: std::hex << std::showbase << (size_t)pointer
893 createAction_str << ">(reinterpret_cast<std::shared_ptr<ROOT::Detail::RDF::RNodeBase>*>("
894 << PrettyPrintAddr(prevNode) << "), new const char*[" << cols.size() << "]{";
895 for (auto i = 0u; i < cols.size(); ++i) {
896 if (i != 0u)
897 createAction_str << ", ";
898 createAction_str << '"' << cols[i] << '"';
899 }
900 createAction_str << "}, " << cols.size() << ", " << nSlots << ", reinterpret_cast<shared_ptr<" << helperArgTypeName
901 << ">*>(" << PrettyPrintAddr(helperArgOnHeap)
902 << "), reinterpret_cast<std::weak_ptr<ROOT::Internal::RDF::RJittedAction>*>("
904 << "), reinterpret_cast<ROOT::Internal::RDF::RColumnRegister*>(" << definesAddr << "));";
905 return createAction_str.str();
906}
907
908bool AtLeastOneEmptyString(const std::vector<std::string_view> strings)
909{
910 for (const auto &s : strings) {
911 if (s.empty())
912 return true;
913 }
914 return false;
915}
916
917std::shared_ptr<RNodeBase> UpcastNode(std::shared_ptr<RNodeBase> ptr)
918{
919 return ptr;
920}
921
922/// Given the desired number of columns and the user-provided list of columns:
923/// * fallback to using the first nColumns default columns if needed (or throw if nColumns > nDefaultColumns)
924/// * check that selected column names refer to valid branches, custom columns or datasource columns (throw if not)
925/// * replace column names from aliases by the actual column name
926/// Return the list of selected column names.
927ColumnNames_t GetValidatedColumnNames(RLoopManager &lm, const unsigned int nColumns, const ColumnNames_t &columns,
928 const RColumnRegister &colRegister, RDataSource *ds)
929{
930 auto selectedColumns = SelectColumns(nColumns, columns, lm.GetDefaultColumnNames());
931
932 for (auto &col : selectedColumns) {
933 col = colRegister.ResolveAlias(col);
934 }
935
936 // Complain if there are still unknown columns at this point
938 ds ? ds->GetColumnNames() : ColumnNames_t{});
939
940 if (!unknownColumns.empty()) {
941 // Some columns are still unknown, we need to understand if the error
942 // should be printed or if the user requested to explicitly disable it.
943 // Look for a possible overlap between the unknown columns and the
944 // columns we should ignore for the purpose of the following exception
945 std::set<std::string> intersection;
946 const auto &colsToIgnore = lm.GetSuppressErrorsForMissingBranches();
947 std::sort(unknownColumns.begin(), unknownColumns.end());
948 std::set_intersection(unknownColumns.cbegin(), unknownColumns.cend(), colsToIgnore.cbegin(), colsToIgnore.cend(),
949 std::inserter(intersection, intersection.begin()));
950 if (intersection.empty()) {
951 std::string errMsg = std::string("Unknown column") + (unknownColumns.size() > 1 ? "s: " : ": ");
952 for (auto &unknownColumn : unknownColumns)
953 errMsg += '"' + unknownColumn + "\", ";
954 errMsg.resize(errMsg.size() - 2); // remove last ", "
955 throw std::runtime_error(errMsg);
956 }
957 }
958
959 return selectedColumns;
960}
961
962std::vector<std::string> GetValidatedArgTypes(const ColumnNames_t &colNames, const RColumnRegister &colRegister,
963 TTree *tree, RDataSource *ds, const std::string &context,
964 bool vector2RVec)
965{
966 auto toCheckedArgType = [&](const std::string &c) {
967 RDFDetail::RDefineBase *define = colRegister.GetDefine(c);
968 const auto colType = ColumnName2ColumnTypeName(c, tree, ds, define, vector2RVec);
969 if (colType.rfind("CLING_UNKNOWN_TYPE", 0) == 0) { // the interpreter does not know this type
970 const auto msg =
971 "The type of custom column \"" + c + "\" (" + colType.substr(19) +
972 ") is not known to the interpreter, but a just-in-time-compiled " + context +
973 " call requires this column. Make sure to create and load ROOT dictionaries for this column's class.";
974 throw std::runtime_error(msg);
975 }
976 return colType;
977 };
978 std::vector<std::string> colTypes;
979 colTypes.reserve(colNames.size());
980 std::transform(colNames.begin(), colNames.end(), std::back_inserter(colTypes), toCheckedArgType);
981 return colTypes;
982}
983
984/// Return a bitset each element of which indicates whether the corresponding element in `selectedColumns` is the
985/// name of a column that must be defined via datasource. All elements of the returned vector are false if no
986/// data-source is present.
987std::vector<bool> FindUndefinedDSColumns(const ColumnNames_t &requestedCols, const ColumnNames_t &definedCols)
988{
989 const auto nColumns = requestedCols.size();
990 std::vector<bool> mustBeDefined(nColumns, false);
991 for (auto i = 0u; i < nColumns; ++i)
993 return mustBeDefined;
994}
995
996void CheckForDuplicateSnapshotColumns(const ColumnNames_t &cols)
997{
998 std::unordered_set<std::string> uniqueCols;
999 for (auto &col : cols) {
1000 if (!uniqueCols.insert(col).second) {
1001 const auto msg = "Error: column \"" + col +
1002 "\" was passed to Snapshot twice. This is not supported: only one of the columns would be "
1003 "readable with RDataFrame.";
1004 throw std::logic_error(msg);
1005 }
1006 }
1007}
1008
1009/// Return copies of colsWithoutAliases and colsWithAliases with size branches for variable-sized array branches added
1010/// in the right positions (i.e. before the array branches that need them).
1011std::pair<std::vector<std::string>, std::vector<std::string>>
1012AddSizeBranches(const std::vector<std::string> &branches, ROOT::RDF::RDataSource *ds,
1013 std::vector<std::string> &&colsWithoutAliases, std::vector<std::string> &&colsWithAliases)
1014{
1015 tree{};
1016 if (auto treeDS = dynamic_cast<ROOT::Internal::RDF::RTTreeDS *>(ds))
1017 treeDS->GetTree();
1018 if (!tree) // nothing to do
1019 return {std::move(colsWithoutAliases), std::move(colsWithAliases)};
1020
1021 assert(colsWithoutAliases.size() == colsWithAliases.size());
1022
1023 auto nCols = colsWithoutAliases.size();
1024 // Use index-iteration as we modify the vector during the iteration.
1025 for (std::size_t i = 0u; i < nCols; ++i) {
1026 const auto &colName = colsWithoutAliases[i];
1028 continue; // this column is not a TTree branch, nothing to do
1029
1030 auto *colName.c_str());
1031 if (!b) // try harder
1032 colName.c_str());
1033 assert(b != nullptr);
1034 auto *leaves = b->GetListOfLeaves();
1035 if (b->IsA() != TBranch::Class() || leaves->GetEntries() != 1)
1036 continue; // this branch is not a variable-sized array, nothing to do
1037
1038 TLeaf *countLeaf = static_cast<TLeaf *>(leaves->At(0))->GetLeafCount();
1039 if (!countLeaf || IsStrInVec(countLeaf->GetName(), colsWithoutAliases))
1040 continue; // not a variable-sized array or the size branch is already there, nothing to do
1041
1042 // otherwise we must insert the size in colsWithoutAliases _and_ colsWithAliases
1043 colsWithoutAliases.insert(colsWithoutAliases.begin() + i, countLeaf->GetName());
1044 colsWithAliases.insert(colsWithAliases.begin() + i, countLeaf->GetName());
1045 ++nCols;
1046 ++i; // as we inserted an element in the vector we iterate over, we need to move the index forward one extra time
1047 }
1048
1049 return {std::move(colsWithoutAliases), std::move(colsWithAliases)};
1050}
1051
1052void RemoveDuplicates(ColumnNames_t &columnNames)
1053{
1054 std::set<std::string> uniqueCols;
1055 columnNames.erase(
1056 std::remove_if(columnNames.begin(), columnNames.end(),
1057 [&uniqueCols](const std::string &colName) { return !uniqueCols.insert(colName).second; }),
1058 columnNames.end());
1059}
1060
1061void RemoveRNTupleSubFields(ColumnNames_t &columnNames)
1062{
1063 ColumnNames_t parentFields;
1064
1065 std::copy_if(columnNames.cbegin(), columnNames.cend(), std::back_inserter(parentFields),
1066 [](const std::string &colName) { return colName.find('.') == std::string::npos; });
1067
1068 columnNames.erase(std::remove_if(columnNames.begin(), columnNames.end(),
1069 [&parentFields](const std::string &colName) {
1070 if (colName.find('.') == std::string::npos)
1071 return false;
1072 const auto parentFieldName = colName.substr(0, colName.find_first_of('.'));
1073 return std::find(parentFields.cbegin(), parentFields.cend(), parentFieldName) !=
1074 parentFields.end();
1075 }),
1076 columnNames.end());
1077}
1078} // namespace RDF
1079} // namespace Internal
1080} // namespace ROOT
#define b(i)
Definition RSha256.hxx:100
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
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 cname
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 text
char name[80]
Definition TGX11.cxx:110
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define gROOT
Definition TROOT.h:414
#define R__LOCKGUARD(mutex)
#define free
Definition civetweb.c:1539
A binder for user-defined columns, variations and aliases.
RDataSource defines an API that RDataFrame can use to read arbitrary data formats.
const_iterator begin() const
const_iterator end() const
static TClass * Class()
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:3074
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition TLeaf.h:57
Basic string class.
Definition TString.h:139
A TTree represents a columnar dataset.
Definition TTree.h:84
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:123
bool IsStrInVec(const std::string &str, const std::vector< std::string > &vec)
Definition RDFUtils.cxx:444
std::string PrettyPrintAddr(const void *const addr)
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:233
std::vector< T > Union(const std::vector< T > &v1, const std::vector< T > &v2)
Return a vector with all elements of v1 and v2 and duplicates removed.
Definition Utils.hxx:270
bool IsInternalColumn(std::string_view colName)
Whether custom column with name colName is an "internal" column such as rdfentry_ or rdfslot_.
Definition RDFUtils.cxx:386
void InterpreterDeclare(const std::string &code)
Declare code in the interpreter via the TInterpreter::Declare method, throw in case of errors.
Definition RDFUtils.cxx:337
std::vector< std::string > ColumnNames_t
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
char * DemangleTypeIdName(const std::type_info &ti, int &errorCode)
Demangle in a portable way the type id name.
BVH_ALWAYS_INLINE T dot(const Vec< T, N > &a, const Vec< T, N > &b)
Definition vec.h:98