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>
20#include "ROOT/RLogger.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 <typeinfo>
60#include <unordered_map>
61#include <unordered_set>
62#include <utility> // for pair
63#include <vector>
64
65namespace ROOT::Detail::RDF {
66class RDefineBase;
67}
68
69namespace {
72
73/// A string expression such as those passed to Filter and Define, digested to a standardized form
74struct ParsedExpression {
75 /// The string expression with the dummy variable names in fVarNames in place of the original column names
76 std::string fExpr;
77 /// The list of valid column names that were used in the original string expression.
78 /// Duplicates are removed and column aliases (created with Alias calls) are resolved.
79 ColumnNames_t fUsedCols;
80 /// The list of variable names used in fExpr, with same ordering and size as fUsedCols
81 ColumnNames_t fVarNames;
82};
83
84/// Look at expression `expr` and return a pair of (column names used, aliases used)
85std::pair<ColumnNames_t, ColumnNames_t> FindUsedColsAndAliases(const std::string &expr,
86 const ROOT::Internal::RDF::RColumnRegister &colRegister,
87 const ColumnNames_t &dataSourceColNames)
88{
89 lexertk::generator tokens;
90 const auto tokensOk = tokens.process(expr);
91 if (!tokensOk) {
92 const auto msg = "Failed to tokenize expression:\n" + expr + "\n\nMake sure it is valid C++.";
93 throw std::runtime_error(msg);
94 }
95
96 std::unordered_set<std::string> usedCols;
97 std::unordered_set<std::string> usedAliases;
98
99 // iterate over tokens in expression and fill usedCols and usedAliases
100 const auto nTokens = tokens.size();
101 const auto kSymbol = lexertk::token::e_symbol;
102 for (auto i = 0u; i < nTokens; ++i) {
103 const auto &tok = tokens[i];
104 // lexertk classifies '&' as e_symbol for some reason
105 if (tok.type != kSymbol || tok.value == "&" || tok.value == "|") {
106 // token is not a potential variable name, skip it
107 continue;
108 }
109 // Skip symbols that are member accesses (obj.method) — they are not column references.
110 // lexertk does not produce dot-prefixed tokens, so the token immediately before a method
111 // name is always the literal "." token when it is a member access.
112 if (i > 0 && tokens[i - 1].value == ".") {
113 continue;
114 }
115
116 ColumnNames_t potentialColNames({tok.value});
117
118 // if token is the start of a dot chain (a.b.c...), a.b, a.b.c etc. are also potential column names
119 auto dotChainKeepsGoing = [&](unsigned int _i) {
120 return _i + 2 <= nTokens && tokens[_i + 1].value == "." && tokens[_i + 2].type == kSymbol;
121 };
122 while (dotChainKeepsGoing(i)) {
123 potentialColNames.emplace_back(potentialColNames.back() + "." + tokens[i + 2].value);
124 i += 2; // consume the tokens we looked at
125 }
126
127 // in an expression such as `a.b`, if `a` is a column alias add it to `usedAliases` and
128 // replace the alias with the real column name in `potentialColNames`.
129 const auto maybeAnAlias = potentialColNames[0]; // intentionally a copy as we'll modify potentialColNames later
130 const auto &resolvedAlias = colRegister.ResolveAlias(maybeAnAlias);
131 if (resolvedAlias != maybeAnAlias) { // this is an alias
132 usedAliases.insert(maybeAnAlias);
133 for (auto &s : potentialColNames)
134 s.replace(0, maybeAnAlias.size(), resolvedAlias);
135 }
136
137 // find the longest potential column name that is an actual column name
138 // (potential columns are sorted by length, so we search from the end to find the longest)
139 auto isRDFColumn = [&](const std::string &col) {
140 if (colRegister.IsDefineOrAlias(col) || IsStrInVec(col, dataSourceColNames))
141 return true;
142 return false;
143 };
144 const auto longestRDFColMatch = std::find_if(potentialColNames.crbegin(), potentialColNames.crend(), isRDFColumn);
145 if (longestRDFColMatch != potentialColNames.crend())
146 usedCols.insert(*longestRDFColMatch);
147 }
148
149 return {{usedCols.begin(), usedCols.end()}, {usedAliases.begin(), usedAliases.end()}};
150}
151
152/// Substitute each '.' in a string with '\.'
153std::string EscapeDots(const std::string &s)
154{
155 TString out(s);
156 TPRegexp dot("\\.");
157 dot.Substitute(out, "\\.", "g");
158 return std::string(std::move(out));
159}
160
161TString ResolveAliases(const TString &expr, const ColumnNames_t &usedAliases,
162 const ROOT::Internal::RDF::RColumnRegister &colRegister)
163{
164 TString out(expr);
165
166 for (const auto &alias : usedAliases) {
167 const auto &col = colRegister.ResolveAlias(alias);
168 TPRegexp replacer("(?<!\\.)\\b" + EscapeDots(alias) + "\\b");
169 replacer.Substitute(out, col.data(), "g");
170 }
171
172 return out;
173}
174
175ParsedExpression ParseRDFExpression(std::string_view expr, const ROOT::Internal::RDF::RColumnRegister &colRegister,
176 const ColumnNames_t &dataSourceColNames)
177{
178 // transform `#var` into `R_rdf_sizeof_var`
179 TString preProcessedExpr(expr);
180 // match #varname at beginning of the sentence or after not-a-word, but exclude preprocessor directives like #ifdef
181 TPRegexp colSizeReplacer(
182 "(^|\\W)#(?!(ifdef|ifndef|if|else|elif|endif|pragma|define|undef|include|line))([a-zA-Z_][a-zA-Z0-9_]*)");
183 colSizeReplacer.Substitute(preProcessedExpr, "$1R_rdf_sizeof_$3", "g");
184
185 ColumnNames_t usedCols;
186 ColumnNames_t usedAliases;
187 std::tie(usedCols, usedAliases) =
188 FindUsedColsAndAliases(std::string(preProcessedExpr), colRegister, dataSourceColNames);
189
190 const auto exprNoAliases = ResolveAliases(preProcessedExpr, usedAliases, colRegister);
191
192 // when we are done, exprWithVars willl be the same as preProcessedExpr but column names will be substituted with
193 // the dummy variable names in varNames
194 TString exprWithVars(exprNoAliases);
195
196 ColumnNames_t varNames(usedCols.size());
197 for (auto i = 0u; i < varNames.size(); ++i)
198 varNames[i] = "var" + std::to_string(i);
199
200 // sort the vector usedColsAndAliases by decreasing length of its elements,
201 // so in case of friends we guarantee we never substitute a column name with another column containing it
202 // ex. without sorting when passing "x" and "fr.x", the replacer would output "var0" and "fr.var0",
203 // because it has already substituted "x", hence the "x" in "fr.x" would be recognized as "var0",
204 // whereas the desired behaviour is handling them as "var0" and "var1"
205 std::sort(usedCols.begin(), usedCols.end(),
206 [](const std::string &a, const std::string &b) { return a.size() > b.size(); });
207 for (const auto &col : usedCols) {
208 const auto varIdx = std::distance(usedCols.begin(), std::find(usedCols.begin(), usedCols.end(), col));
209 TPRegexp replacer("(?<!\\.)\\b" + EscapeDots(col) + "\\b");
210 replacer.Substitute(exprWithVars, varNames[varIdx], "g");
211 }
212
213 return ParsedExpression{std::string(std::move(exprWithVars)), std::move(usedCols), std::move(varNames)};
214}
215
216/// Return the static global map of Filter/Define functions that have been jitted.
217/// It's used to check whether a given expression has already been jitted, and
218/// to look up its associated variable name if it is.
219/// Keys in the map are the body of the expression, values are the name of the
220/// jitted variable that corresponds to that expression. For example, for:
221/// auto f1(){ return 42; }
222/// key would be "(){ return 42; }" and value would be "f1".
223std::unordered_map<std::string, std::string> &GetJittedExprs() {
224 static std::unordered_map<std::string, std::string> jittedExpressions;
225 return jittedExpressions;
226}
227
228std::string BuildFunctionString(const std::string &expr, const ColumnNames_t &vars, const ColumnNames_t &varTypes,
229 bool isSingleColumn = false, const std::string &varyColType = "")
230{
231 assert(vars.size() == varTypes.size());
232
233 TPRegexp re(R"(\breturn\b)");
234 const bool hasReturnStmt = re.MatchB(expr);
235
236 static const std::vector<std::string> fundamentalTypes = {
237 "int",
238 "signed",
239 "signed int",
240 "Int_t",
241 "unsigned",
242 "unsigned int",
243 "UInt_t",
244 "double",
245 "Double_t",
246 "float",
247 "Float_t",
248 "char",
249 "Char_t",
250 "unsigned char",
251 "UChar_t",
252 "bool",
253 "Bool_t",
254 "short",
255 "short int",
256 "Short_t",
257 "long",
258 "long int",
259 "long long int",
260 "Long64_t",
261 "unsigned long",
262 "unsigned long int",
263 "ULong64_t",
264 "std::size_t",
265 "size_t",
266 "Ssiz_t"
267 };
268
269 std::stringstream ss;
270 ss << "(";
271 for (auto i = 0u; i < vars.size(); ++i) {
272 std::string fullType;
273 const auto &type = varTypes[i];
274 if (std::find(fundamentalTypes.begin(), fundamentalTypes.end(), type) != fundamentalTypes.end()) {
275 // pass it by const value to help detect common mistakes such as if(x = 3)
276 fullType = "const " + type + " ";
277 } else {
278 // We pass by reference to avoid expensive copies
279 // It can't be const reference in general, as users might want/need to call non-const methods on the values
280 fullType = type + "& ";
281 }
282 ss << fullType << vars[i] << ", ";
283 }
284 if (!vars.empty())
285 ss.seekp(-2, ss.cur);
286
287 // When building the function expression for a Vary call, we try to help the
288 // user by removing the need to explicitly write the vector return type.
289 // For now, Vary works by returning a (nested) RVec, depending on how many
290 // variables need to vary in lockstep.
291 auto finalizeExprForVary = [&]() {
292 std::string trailRetType{};
293 // Trim formatting characters at the extremes of the user expression
294 auto first_not_space = expr.find_first_not_of(" \n\t");
295 auto last_not_space = expr.find_last_not_of(" \n\t");
296 if (first_not_space != std::string::npos && last_not_space != std::string::npos && expr[first_not_space] == '{' &&
297 expr[last_not_space] == '}') {
298 // User expression is of type '{...}', a potential constructor for an
299 // RVec. At the same time, they have not decided the RVec return type
300 // Add trailing return type for the convenience of the user
301 // The innermost value type is by default the type of the first given column
302 trailRetType = " -> ";
303 if (isSingleColumn)
304 trailRetType += "ROOT::RVec<" + varyColType + ">";
305 else
306 trailRetType += "ROOT::RVec<ROOT::RVec<" + varyColType + ">>";
307 trailRetType += ' ';
308 }
309 std::string trailRetToken{trailRetType.empty() ? ") {" : ')' + trailRetType + '{'};
310 if (!hasReturnStmt)
311 trailRetToken += " return ";
312 return trailRetToken;
313 };
314
315 if (!varyColType.empty())
316 ss << finalizeExprForVary();
317 else
318 ss << (hasReturnStmt ? ") {" : ") { return ");
319
320 // Must inject \n to avoid cases where the user puts a comment after the expression
321 ss << expr << "\n;}\n";
322
323 return ss.str();
324}
325
326/// Declare a function to the interpreter in namespace R_rdf, return the name of the jitted function.
327/// If the function is already in GetJittedExprs, return the name for the function that has already been jitted.
328std::string DeclareFunction(const std::string &expr, const ColumnNames_t &vars, const ColumnNames_t &varTypes,
329 bool isSingleColumn = false, const std::string &varyColType = "")
330{
332
333 const auto funcCode = BuildFunctionString(expr, vars, varTypes, isSingleColumn, varyColType);
334 auto &exprMap = GetJittedExprs();
335 const auto exprIt = exprMap.find(funcCode);
336 if (exprIt != exprMap.end()) {
337 // expression already there
338 const auto funcName = exprIt->second;
339 return funcName;
340 }
341
342 // new expression
343 const auto funcBaseName = "func" + std::to_string(exprMap.size());
344 const auto funcFullName = "R_rdf::" + funcBaseName;
345
346 const auto toDeclare = "namespace R_rdf {\nauto " + funcBaseName + funcCode + "\nusing " + funcBaseName +
347 "_ret_t = typename ROOT::TypeTraits::CallableTraits<decltype(" + funcBaseName +
348 ")>::ret_type;\n}";
350
351 // InterpreterDeclare could throw. If it doesn't, mark the function as already jitted
352 exprMap.insert({funcCode, funcFullName});
353
354 return funcFullName;
355}
356
357/// Each jitted function comes with a func_ret_t type alias for its return type.
358/// Resolve that alias and return the true type as string.
359std::string RetTypeOfFunc(const std::string &funcName)
360{
361 const auto dt = gROOT->GetType((funcName + "_ret_t").c_str());
362 R__ASSERT(dt != nullptr);
363 const auto type = dt->GetFullTypeName();
364 return type;
365}
366
367[[noreturn]] void
368ThrowJitBuildActionHelperTypeError(const std::string &actionTypeNameBase, const std::type_info &helperArgType)
369{
370 int err = 0;
371 const char *cname = TClassEdit::DemangleTypeIdName(helperArgType, err);
372 std::string actionHelperTypeName = cname;
373 delete[] cname;
374 if (err != 0)
375 actionHelperTypeName = helperArgType.name();
376
377 std::string exceptionText =
378 "RDataFrame::Jit: cannot just-in-time compile a \"" + actionTypeNameBase + "\" action using helper type \"" +
379 actionHelperTypeName +
380 "\". This typically happens in a custom `Fill` or `Book` invocation where the types of the input columns have "
381 "not been specified as template parameters and the ROOT interpreter has no knowledge of this type of action "
382 "helper. Please add template parameters for the types of the input columns to avoid jitting this action (i.e. "
383 "`df.Fill<float>(..., {\"x\"})`, where `float` is the type of `x`) or declare the action helper type to the "
384 "interpreter, e.g. via gInterpreter->Declare.";
385
386 throw std::runtime_error(exceptionText);
387}
388
389} // anonymous namespace
390
391namespace ROOT {
392namespace Internal {
393namespace RDF {
394
395/// Take a list of column names, return that list with entries starting by '#' filtered out.
396/// The function throws when filtering out a column this way.
397ColumnNames_t FilterArraySizeColNames(const ColumnNames_t &columnNames, const std::string &action)
398{
399 ColumnNames_t columnListWithoutSizeColumns;
400 ColumnNames_t filteredColumns;
401 std::copy_if(columnNames.begin(), columnNames.end(), std::back_inserter(columnListWithoutSizeColumns),
402 [&](const std::string &name) {
403 if (name[0] == '#') {
404 filteredColumns.emplace_back(name);
405 return false;
406 } else {
407 return true;
408 }
409 });
410
411 if (!filteredColumns.empty()) {
412 std::string msg = "Column name(s) {";
413 for (auto &c : filteredColumns)
414 msg += c + ", ";
415 msg[msg.size() - 2] = '}';
416 msg += "will be ignored. Please go through a valid Alias to " + action + " an array size column";
417 throw std::runtime_error(msg);
418 }
419
420 return columnListWithoutSizeColumns;
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);
455 char *tn = TClassEdit::DemangleTypeIdName(typeInfo, dummy);
456 std::string tname(tn);
457 free(tn);
458 return tname;
459}
460
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 &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 if (std::find(dataSourceColumns.begin(), dataSourceColumns.end(), definedColView) != dataSourceColumns.end())
509 error =
510 "A column with that name is already present in the input data source. Use Redefine to force redefinition.";
511
512 if (!error.empty()) {
513 error = "RDataFrame::" + where + ": cannot define column \"" + std::string(definedColView) + "\". " + error;
514 throw std::runtime_error(error);
515 }
516}
517
518/// Throw if column `definedColView` is _not_ already there.
519void CheckForDefinition(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister,
520 const ColumnNames_t &dataSourceColumns)
521{
522 std::string error{};
523
524 if (colRegister.IsAlias(definedColView)) {
525 error = "An alias with that name, pointing to column \"" + std::string(colRegister.ResolveAlias(definedColView)) +
526 "\", already exists. Aliases cannot be Redefined or Varied.";
527 }
528
529 if (error.empty()) {
530 const bool isAlreadyDefined = colRegister.IsDefineOrAlias(definedColView);
531 const bool isADSColumn =
532 std::find(dataSourceColumns.begin(), dataSourceColumns.end(), definedColView) != dataSourceColumns.end();
533
534 if (!isAlreadyDefined && !isADSColumn)
535 error = "No column with that name was found in the dataset. Use Define to create a new column.";
536 }
537
538 if (!error.empty()) {
539 if (where == "DefaultValueFor")
540 error = "RDataFrame::" + where + ": cannot provide default values for column \"" +
541 std::string(definedColView) + "\". " + error;
542 else
543 error = "RDataFrame::" + where + ": cannot redefine or vary column \"" + std::string(definedColView) + "\". " +
544 error;
545 throw std::runtime_error(error);
546 }
547}
548
549/// Throw if the column has systematic variations attached.
550void CheckForNoVariations(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister)
551{
552 const std::string definedCol(definedColView);
553 const auto &variationDeps = colRegister.GetVariationDeps(definedCol);
554 if (!variationDeps.empty()) {
555 if (where == "Redefine") {
556 const std::string error = "RDataFrame::" + where + ": cannot redefine column \"" + definedCol +
557 "\". The column depends on one or more systematic variations and re-defining varied "
558 "columns is not supported.";
559 throw std::runtime_error(error);
560 } else if (where == "DefaultValueFor") {
561 const std::string error = "RDataFrame::" + where + ": cannot provide a default value for column \"" +
562 definedCol +
563 "\". The column depends on one or more systematic variations and it should not be "
564 "possible to have missing values in varied columns.";
565 throw std::runtime_error(error);
566 } else {
567 const std::string error =
568 "RDataFrame::" + where + ": this operation cannot work with columns that depend on systematic variations.";
569 throw std::runtime_error(error);
570 }
571 }
572}
573
574void CheckTypesAndPars(unsigned int nTemplateParams, unsigned int nColumnNames)
575{
576 if (nTemplateParams != nColumnNames) {
577 std::string err_msg = "The number of template parameters specified is ";
578 err_msg += std::to_string(nTemplateParams);
579 err_msg += " while ";
580 err_msg += std::to_string(nColumnNames);
581 err_msg += " columns have been specified.";
582 throw std::runtime_error(err_msg);
583 }
584}
585
586/// Choose between local column names or default column names, throw in case of errors.
587const ColumnNames_t
588SelectColumns(unsigned int nRequiredNames, const ColumnNames_t &names, const ColumnNames_t &defaultNames)
589{
590 if (names.empty()) {
591 // use default column names
592 if (defaultNames.size() < nRequiredNames)
593 throw std::runtime_error(
594 std::to_string(nRequiredNames) + " column name" + (nRequiredNames == 1 ? " is" : "s are") +
595 " required but none were provided and the default list has size " + std::to_string(defaultNames.size()));
596 // return first nRequiredNames default column names
597 return ColumnNames_t(defaultNames.begin(), defaultNames.begin() + nRequiredNames);
598 } else {
599 // use column names provided by the user to this particular transformation/action
600 if (names.size() != nRequiredNames) {
601 auto msg = std::to_string(nRequiredNames) + " column name" + (nRequiredNames == 1 ? " is" : "s are") +
602 " required but " + std::to_string(names.size()) + (names.size() == 1 ? " was" : " were") +
603 " provided:";
604 for (const auto &name : names)
605 msg += " \"" + name + "\",";
606 msg.back() = '.';
607 throw std::runtime_error(msg);
608 }
609 return names;
610 }
611}
612
613ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, const RColumnRegister &definedCols,
614 const ColumnNames_t &dataSourceColumns)
615{
616 ColumnNames_t unknownColumns;
617 for (auto &column : requiredCols) {
618 if (definedCols.IsDefineOrAlias(column))
619 continue;
620 const auto isDataSourceColumn =
621 std::find(dataSourceColumns.begin(), dataSourceColumns.end(), column) != dataSourceColumns.end();
622 if (isDataSourceColumn)
623 continue;
624 unknownColumns.emplace_back(column);
625 }
626 return unknownColumns;
627}
628
629std::vector<std::string> GetFilterNames(const std::shared_ptr<RLoopManager> &loopManager)
630{
631 return loopManager->GetFiltersNames();
632}
633
634ParsedTreePath ParseTreePath(std::string_view fullTreeName)
635{
636 // split name into directory and treename if needed
637 std::string_view dirName = "";
638 std::string_view treeName = fullTreeName;
639 const auto lastSlash = fullTreeName.rfind('/');
640 if (std::string_view::npos != lastSlash) {
641 dirName = treeName.substr(0, lastSlash);
642 treeName = treeName.substr(lastSlash + 1, treeName.size());
643 }
644 return {std::string(treeName), std::string(dirName)};
645}
646
647std::string PrettyPrintAddr(const void *const addr)
648{
649 std::stringstream s;
650 // Windows-friendly
651 s << std::hex << std::showbase << reinterpret_cast<size_t>(addr);
652 return s.str();
653}
654
655/// Book the jitting of a Filter call
656std::shared_ptr<RDFDetail::RJittedFilter>
657BookFilterJit(std::shared_ptr<RDFDetail::RNodeBase> prevNode, std::string_view name, std::string_view expression,
658 const RColumnRegister &colRegister, TTree *tree, RDataSource *ds)
659{
660 const auto &dsColumns = ds ? ds->GetColumnNames() : ColumnNames_t{};
661
662 const auto parsedExpr = ParseRDFExpression(expression, colRegister, dsColumns);
663 const auto exprVarTypes =
664 GetValidatedArgTypes(parsedExpr.fUsedCols, colRegister, tree, ds, "Filter", /*vector2RVec=*/true);
665 const auto funcName = DeclareFunction(parsedExpr.fExpr, parsedExpr.fVarNames, exprVarTypes);
666 const auto type = RetTypeOfFunc(funcName);
667 if (type != "bool")
668 throw std::runtime_error("Filter: the following expression does not evaluate to bool:\n" +
669 std::string(expression));
670
671 auto *lm = prevNode->GetLoopManagerUnchecked();
672 const auto jittedFilter = std::make_shared<RDFDetail::RJittedFilter>(
673 lm, name, Union(colRegister.GetVariationDeps(parsedExpr.fUsedCols), prevNode->GetVariations()), prevNode);
674
675 // Produce code snippet that creates the filter and registers it with the corresponding RJittedFilter
676 std::stringstream filterInvocation;
677 filterInvocation << "(const std::vector<std::string> &colNames, "
678 << "ROOT::Internal::RDF::RColumnRegister &colRegister, "
679 << "ROOT::Detail::RDF::RLoopManager &lm, "
680 << "void *jittedFilter, "
681 << "std::shared_ptr<void> *) {\n";
682 filterInvocation << " ROOT::Internal::RDF::JitFilterHelper(" << funcName << ", "
683 << "colNames, "
684 << "colRegister, "
685 << "lm, "
686 << "reinterpret_cast<ROOT::Detail::RDF::RJittedFilter*>(jittedFilter)"
687 << ");\n}\n";
688 lm->RegisterJitHelperCall(filterInvocation.str(),
689 std::make_unique<ROOT::Internal::RDF::RColumnRegister>(colRegister), parsedExpr.fUsedCols,
690 jittedFilter);
691
692 return jittedFilter;
693}
694
695/// Book the jitting of a Define call
696std::shared_ptr<RJittedDefine> BookDefineJit(std::string_view name, std::string_view expression, RLoopManager &lm,
697 RDataSource *ds, const RColumnRegister &colRegister)
698{
699 const auto &dsColumns = ds ? ds->GetColumnNames() : ColumnNames_t{};
700
701 const auto parsedExpr = ParseRDFExpression(expression, colRegister, dsColumns);
702 const auto exprVarTypes =
703 GetValidatedArgTypes(parsedExpr.fUsedCols, colRegister, nullptr, ds, "Define", /*vector2RVec=*/true);
704 const auto funcName = DeclareFunction(parsedExpr.fExpr, parsedExpr.fVarNames, exprVarTypes);
705 const auto type = RetTypeOfFunc(funcName);
706
707 auto jittedDefine = std::make_shared<RDFDetail::RJittedDefine>(name, type, lm, colRegister, parsedExpr.fUsedCols);
708
709 // lifetime of pointees:
710 // - lm is the loop manager, and if that goes out of scope jitting does not happen at all (i.e. will always be valid)
711 // - jittedDefine: heap-allocated weak_ptr that will be deleted by JitDefineHelper after usage
712 // - definesAddr: heap-allocated, will be deleted by JitDefineHelper after usage
713 std::stringstream defineInvocation;
714 defineInvocation << "(const std::vector<std::string> &colNames, "
715 << "ROOT::Internal::RDF::RColumnRegister &colRegister, "
716 << "ROOT::Detail::RDF::RLoopManager &lm, "
717 << "void *jittedDefine, "
718 << "std::shared_ptr<void> *) {\n";
719 defineInvocation << " ROOT::Internal::RDF::JitDefineHelper<ROOT::Internal::RDF::DefineTypes::RDefineTag>("
720 << funcName << ", "
721 << "colNames, "
722 << "colRegister, "
723 << "lm, "
724 << "reinterpret_cast<ROOT::Detail::RDF::RJittedDefine *>(jittedDefine)"
725 << ");\n}\n";
726 lm.RegisterJitHelperCall(defineInvocation.str(), std::make_unique<ROOT::Internal::RDF::RColumnRegister>(colRegister),
727 parsedExpr.fUsedCols, jittedDefine);
728
729 return jittedDefine;
730}
731
732/// Book the jitting of a DefinePerSample call
733std::shared_ptr<RJittedDefine> BookDefinePerSampleJit(std::string_view name, std::string_view expression,
734 RLoopManager &lm, const RColumnRegister &colRegister)
735{
736 const auto funcName = DeclareFunction(std::string(expression), {"rdfslot_", "rdfsampleinfo_"},
737 {"unsigned int", "const ROOT::RDF::RSampleInfo"});
738 const auto retType = RetTypeOfFunc(funcName);
739
740 auto jittedDefine = std::make_shared<RDFDetail::RJittedDefine>(name, retType, lm, colRegister, ColumnNames_t{});
741
742 // lifetime of pointees:
743 // - lm is the loop manager, and if that goes out of scope jitting does not happen at all (i.e. will always be valid)
744 // - jittedDefine: heap-allocated weak_ptr that will be deleted by JitDefineHelper after usage
745 // - definesAddr: heap-allocated, will be deleted by JitDefineHelper after usage
746 std::stringstream defineInvocation;
747 defineInvocation << "(const std::vector<std::string> &colNames, "
748 << "ROOT::Internal::RDF::RColumnRegister &colRegister, "
749 << "ROOT::Detail::RDF::RLoopManager &lm, "
750 << "void *jittedDefine, "
751 << "std::shared_ptr<void> *) {\n";
752 defineInvocation << " ROOT::Internal::RDF::JitDefineHelper<ROOT::Internal::RDF::DefineTypes::RDefinePerSampleTag>("
753 << funcName << ", "
754 << "colNames, "
755 << "colRegister, "
756 << "lm, "
757 << "reinterpret_cast<ROOT::Detail::RDF::RJittedDefine *>(jittedDefine)"
758 << ");\n}\n";
759 lm.RegisterJitHelperCall(defineInvocation.str(), std::make_unique<ROOT::Internal::RDF::RColumnRegister>(colRegister),
760 {}, jittedDefine);
761 return jittedDefine;
762}
763
764/// Book the jitting of a Vary call
765std::shared_ptr<RJittedVariation>
766BookVariationJit(const std::vector<std::string> &colNames, std::string_view variationName,
767 const std::vector<std::string> &variationTags, std::string_view expression, RLoopManager &lm,
768 RDataSource *ds, const RColumnRegister &colRegister, bool isSingleColumn,
769 const std::string &varyColType)
770{
771 const auto &dsColumns = ds ? ds->GetColumnNames() : ColumnNames_t{};
772
773 const auto parsedExpr = ParseRDFExpression(expression, colRegister, dsColumns);
774 const auto exprVarTypes =
775 GetValidatedArgTypes(parsedExpr.fUsedCols, colRegister, nullptr, ds, "Vary", /*vector2RVec=*/true);
776 const auto funcName =
777 DeclareFunction(parsedExpr.fExpr, parsedExpr.fVarNames, exprVarTypes, isSingleColumn, varyColType);
778 const auto type = RetTypeOfFunc(funcName);
779
780 if (type.rfind("ROOT::VecOps::RVec", 0) != 0) {
781 throw std::runtime_error(
782 "Jitted Vary expressions must return an RVec object. The following expression return type is '" + type +
783 "' instead:\n" + parsedExpr.fExpr);
784 }
785
786 auto jittedVariation = std::make_shared<RJittedVariation>(colNames, variationName, variationTags, type, colRegister,
787 lm, parsedExpr.fUsedCols);
788
789 // build invocation to JitVariationHelper
790 // variation tag (array of strings) passed as const char** plus size.
791 // lifetime of pointees:
792 // - lm is the loop manager, and if that goes out of scope jitting does not happen at all (i.e. will always be valid)
793 // - jittedVariation: heap-allocated weak_ptr that will be deleted by JitDefineHelper after usage
794 // - definesAddr: heap-allocated, will be deleted by JitDefineHelper after usage
795 // - variedColsOnHeap: deleted by registration function
796 std::stringstream varyInvocation;
797 varyInvocation << "(const std::vector<std::string> &inputColNames, "
798 << "ROOT::Internal::RDF::RColumnRegister &colRegister, "
799 << "ROOT::Detail::RDF::RLoopManager &lm, "
800 << "void *jittedVariation, "
801 << "std::shared_ptr<void> *helperArg) {\n";
802 varyInvocation
803 << " auto *variedColNamesAndTags = reinterpret_cast<std::shared_ptr<std::pair<std::vector<std::string>, "
804 "std::vector<std::string>>> *>(helperArg);"
805 << " ROOT::Internal::RDF::JitVariationHelper<" << (isSingleColumn ? "true" : "false") << ">(" << funcName
806 << ", "
807 << "inputColNames, "
808 << "colRegister, "
809 << "lm, "
810 << "reinterpret_cast<ROOT::Internal::RDF::RJittedVariation *>(jittedVariation), "
811 << "(*variedColNamesAndTags)->first, "
812 << "(*variedColNamesAndTags)->second"
813 << ");\n}\n";
815 varyInvocation.str(), std::make_unique<ROOT::Internal::RDF::RColumnRegister>(colRegister), parsedExpr.fUsedCols,
816 jittedVariation,
817 std::make_shared<std::pair<std::vector<std::string>, std::vector<std::string>>>(colNames, variationTags));
818 return jittedVariation;
819}
820
821// Jit and call something equivalent to "this->BuildAndBook<ColTypes...>(params...)"
822// (see comments in the body for actual jitted code)
823std::string JitBuildAction(const ColumnNames_t &cols, const std::type_info &helperArgType, const std::type_info &at,
824 TTree *tree, const unsigned int nSlots, const RColumnRegister &colRegister, RDataSource *ds,
825 const bool vector2RVec)
826{
827 // retrieve type of action as a string
828 auto actionTypeClass = TClass::GetClass(at);
829 if (!actionTypeClass) {
830 std::string exceptionText = "An error occurred while inferring the action type of the operation.";
831 throw std::runtime_error(exceptionText);
832 }
833 const std::string actionTypeName = actionTypeClass->GetName();
834 const std::string actionTypeNameBase = actionTypeName.substr(actionTypeName.rfind(':') + 1);
835
836 // retrieve type of result of the action as a string
837 const auto helperArgTypeName = TypeID2TypeName(helperArgType);
838 if (helperArgTypeName.empty()) {
839 ThrowJitBuildActionHelperTypeError(actionTypeNameBase, helperArgType);
840 }
841
842 // Build a call to CallBuildAction with the appropriate argument. When run through the interpreter, this code will
843 // just-in-time create an RAction object and it will assign it to its corresponding RJittedAction.
844 std::stringstream createAction_str;
845 createAction_str << "(const std::vector<std::string> &colNames, "
846 << "ROOT::Internal::RDF::RColumnRegister &colRegister, "
847 << "ROOT::Detail::RDF::RLoopManager &lm, "
848 << "void *jittedAction, "
849 << "std::shared_ptr<void> *helperArg) {\n";
850 createAction_str << " ROOT::Internal::RDF::CallBuildAction<" << actionTypeName;
851 const auto columnTypeNames = GetValidatedArgTypes(cols, colRegister, tree, ds, actionTypeNameBase, vector2RVec);
852 for (auto &colType : columnTypeNames)
853 createAction_str << ", " << colType;
854 createAction_str << ">("
855 << "colNames, "
856 << "colRegister, "
857 << "lm, "
858 << "reinterpret_cast<ROOT::Internal::RDF::RJittedAction *>(jittedAction), " << nSlots << ", "
859 << "reinterpret_cast<std::shared_ptr<" << helperArgTypeName << "> *>(helperArg)"
860 << ");\n}\n";
861 return createAction_str.str();
862}
863
864bool AtLeastOneEmptyString(const std::vector<std::string_view> strings)
865{
866 for (const auto &s : strings) {
867 if (s.empty())
868 return true;
869 }
870 return false;
871}
872
873std::shared_ptr<RNodeBase> UpcastNode(std::shared_ptr<RNodeBase> ptr)
874{
875 return ptr;
876}
877
878/// Given the desired number of columns and the user-provided list of columns:
879/// * fallback to using the first nColumns default columns if needed (or throw if nColumns > nDefaultColumns)
880/// * check that selected column names refer to valid branches, custom columns or datasource columns (throw if not)
881/// * replace column names from aliases by the actual column name
882/// Return the list of selected column names.
883ColumnNames_t GetValidatedColumnNames(RLoopManager &lm, const unsigned int nColumns, const ColumnNames_t &columns,
884 const RColumnRegister &colRegister, RDataSource *ds)
885{
886 auto selectedColumns = SelectColumns(nColumns, columns, lm.GetDefaultColumnNames());
887
888 for (auto &col : selectedColumns) {
889 col = colRegister.ResolveAlias(col);
890 }
891
892 // Complain if there are still unknown columns at this point
893 auto unknownColumns = FindUnknownColumns(selectedColumns, colRegister, ds ? ds->GetColumnNames() : ColumnNames_t{});
894
895 if (!unknownColumns.empty()) {
896 // Some columns are still unknown, we need to understand if the error
897 // should be printed or if the user requested to explicitly disable it.
898 // Look for a possible overlap between the unknown columns and the
899 // columns we should ignore for the purpose of the following exception
900 std::set<std::string> intersection;
901 const auto &colsToIgnore = lm.GetSuppressErrorsForMissingBranches();
902 std::sort(unknownColumns.begin(), unknownColumns.end());
903 std::set_intersection(unknownColumns.cbegin(), unknownColumns.cend(), colsToIgnore.cbegin(), colsToIgnore.cend(),
904 std::inserter(intersection, intersection.begin()));
905 if (intersection.empty()) {
906 std::string errMsg = std::string("Unknown column") + (unknownColumns.size() > 1 ? "s: " : ": ");
907 for (auto &unknownColumn : unknownColumns)
908 errMsg += '"' + unknownColumn + "\", ";
909 errMsg.resize(errMsg.size() - 2); // remove last ", "
910 throw std::runtime_error(errMsg);
911 }
912 }
913
914 return selectedColumns;
915}
916
917std::vector<std::string> GetValidatedArgTypes(const ColumnNames_t &colNames, const RColumnRegister &colRegister,
918 TTree *tree, RDataSource *ds, const std::string &context,
919 bool vector2RVec)
920{
921 auto toCheckedArgType = [&](const std::string &c) {
922 RDFDetail::RDefineBase *define = colRegister.GetDefine(c);
923 const auto colType = ColumnName2ColumnTypeName(c, tree, ds, define, vector2RVec);
924 if (colType.rfind("CLING_UNKNOWN_TYPE", 0) == 0) { // the interpreter does not know this type
925 const auto msg =
926 "The type of custom column \"" + c + "\" (" + colType.substr(19) +
927 ") is not known to the interpreter, but a just-in-time-compiled " + context +
928 " call requires this column. Make sure to create and load ROOT dictionaries for this column's class.";
929 throw std::runtime_error(msg);
930 }
931 return colType;
932 };
933 std::vector<std::string> colTypes;
934 colTypes.reserve(colNames.size());
935 std::transform(colNames.begin(), colNames.end(), std::back_inserter(colTypes), toCheckedArgType);
936 return colTypes;
937}
938
940{
941 std::unordered_set<std::string> uniqueCols;
942 for (auto &col : cols) {
943 if (!uniqueCols.insert(col).second) {
944 const auto msg = "Error: column \"" + col +
945 "\" was passed to Snapshot twice. This is not supported: only one of the columns would be "
946 "readable with RDataFrame.";
947 throw std::logic_error(msg);
948 }
949 }
950}
951
953{
954 const ROOT::RDF::RSnapshotOptions defaultSnapshotOpts;
955 std::string optionName;
956
959 if (opts.fApproxZippedClusterSize != defaultSnapshotOpts.fApproxZippedClusterSize) {
960 optionName = "fApproxZippedClusterSize";
961 } else if (opts.fMaxUnzippedClusterSize != defaultSnapshotOpts.fMaxUnzippedClusterSize) {
962 optionName = "fMaxUnzippedClusterSize";
963 } else if (opts.fInitialUnzippedPageSize != defaultSnapshotOpts.fInitialUnzippedPageSize) {
964 optionName = "fInitialUnzippedPageSize";
965 } else if (opts.fMaxUnzippedPageSize != defaultSnapshotOpts.fMaxUnzippedPageSize) {
966 optionName = "fMaxUnzippedPageSize";
967 } else if (opts.fEnablePageChecksums != defaultSnapshotOpts.fEnablePageChecksums) {
968 optionName = "fEnablePageChecksums";
969 } else if (opts.fEnableSamePageMerging != defaultSnapshotOpts.fEnableSamePageMerging) {
970 optionName = "fEnableSamePageMerging";
971 }
972
973 if (!optionName.empty()) {
974 Warning("Snapshot",
975 "The RNTuple-specific %s option in RSnapshotOptions has been set, but the output format is "
976 "set to TTree, so this option won't have any effect. Use the other options available in "
977 "RSnapshotOptions to "
978 "configure the output TTree. Alternatively, change fOutputFormat to snapshot to RNTuple instead.",
979 optionName.c_str());
980 }
982 if (opts.fAutoFlush != defaultSnapshotOpts.fAutoFlush) {
983 optionName = "fAutoFlush";
984 } else if (opts.fSplitLevel != defaultSnapshotOpts.fSplitLevel) {
985 optionName = "fSplitLevel";
986 } else if (opts.fBasketSize != defaultSnapshotOpts.fBasketSize) {
987 optionName = "fBasketSize";
988 }
989
990 if (!optionName.empty()) {
991 Warning(
992 "Snapshot",
993 "The TTree-specific %s option in RSnapshotOptions has been set, but the output format is set to RNTuple, "
994 "so this option won't have any effect. Use the fNTupleWriteOptions option available in RSnapshotOptions to "
995 "configure the output RNTuple. Alternatively, change fOutputFormat to snapshot to TTree instead.",
996 optionName.c_str());
997 }
998 }
999}
1000
1001/// Return copies of colsWithoutAliases and colsWithAliases with size branches for variable-sized array branches added
1002/// in the right positions (i.e. before the array branches that need them).
1003std::pair<std::vector<std::string>, std::vector<std::string>>
1004AddSizeBranches(ROOT::RDF::RDataSource *ds, std::vector<std::string> &&colsWithoutAliases,
1005 std::vector<std::string> &&colsWithAliases)
1006{
1007 TTree *tree{};
1008 if (auto treeDS = dynamic_cast<ROOT::Internal::RDF::RTTreeDS *>(ds))
1009 tree = treeDS->GetTree();
1010 if (!tree) // nothing to do
1011 return {std::move(colsWithoutAliases), std::move(colsWithAliases)};
1012
1013 assert(colsWithoutAliases.size() == colsWithAliases.size());
1014
1015 auto nCols = colsWithoutAliases.size();
1016 // Use index-iteration as we modify the vector during the iteration.
1017 for (std::size_t i = 0u; i < nCols; ++i) {
1018 const auto &colName = colsWithoutAliases[i];
1019
1020 auto *b = tree->GetBranch(colName.c_str());
1021 if (!b) // try harder
1022 b = tree->FindBranch(colName.c_str());
1023
1024 if (!b)
1025 continue;
1026
1027 auto *leaves = b->GetListOfLeaves();
1028 if (b->IsA() != TBranch::Class() || leaves->GetEntries() != 1)
1029 continue; // this branch is not a variable-sized array, nothing to do
1030
1031 TLeaf *countLeaf = static_cast<TLeaf *>(leaves->At(0))->GetLeafCount();
1032 if (!countLeaf || IsStrInVec(countLeaf->GetName(), colsWithoutAliases))
1033 continue; // not a variable-sized array or the size branch is already there, nothing to do
1034
1035 // otherwise we must insert the size in colsWithoutAliases _and_ colsWithAliases
1036 colsWithoutAliases.insert(colsWithoutAliases.begin() + i, countLeaf->GetName());
1037 colsWithAliases.insert(colsWithAliases.begin() + i, countLeaf->GetName());
1038 ++nCols;
1039 ++i; // as we inserted an element in the vector we iterate over, we need to move the index forward one extra time
1040 }
1041
1042 return {std::move(colsWithoutAliases), std::move(colsWithAliases)};
1043}
1044
1046{
1047 std::set<std::string> uniqueCols;
1048 columnNames.erase(
1049 std::remove_if(columnNames.begin(), columnNames.end(),
1050 [&uniqueCols](const std::string &colName) { return !uniqueCols.insert(colName).second; }),
1051 columnNames.end());
1052}
1053
1055{
1056 ColumnNames_t parentFields;
1057
1058 std::copy_if(columnNames.cbegin(), columnNames.cend(), std::back_inserter(parentFields),
1059 [](const std::string &colName) { return colName.find('.') == std::string::npos; });
1060
1061 columnNames.erase(std::remove_if(columnNames.begin(), columnNames.end(),
1062 [&parentFields](const std::string &colName) {
1063 if (colName.find('.') == std::string::npos)
1064 return false;
1065 const auto parentFieldName = colName.substr(0, colName.find_first_of('.'));
1066 return std::find(parentFields.cbegin(), parentFields.cend(), parentFieldName) !=
1067 parentFields.end();
1068 }),
1069 columnNames.end());
1070}
1071} // namespace RDF
1072} // namespace Internal
1073} // namespace ROOT
1074
1075namespace {
1076void AddDataSourceColumn(const std::string &colName, const std::type_info &typeID, ROOT::Detail::RDF::RLoopManager &lm,
1078{
1079
1080 if (colRegister.IsDefineOrAlias(colName))
1081 return;
1082
1083 if (lm.HasDataSourceColumnReaders(colName, typeID))
1084 return;
1085
1086 if (!ds.HasColumn(colName) &&
1088 return;
1089
1090 const auto nSlots = lm.GetNSlots();
1091 std::vector<std::unique_ptr<ROOT::Detail::RDF::RColumnReaderBase>> colReaders;
1092 colReaders.reserve(nSlots);
1093 // TODO consider changing the interface so we return all of these for all slots in one go
1094 for (auto slot = 0u; slot < nSlots; ++slot)
1095 colReaders.emplace_back(
1096 ROOT::Internal::RDF::CreateColumnReader(ds, slot, colName, typeID, /*treeReader*/ nullptr));
1097
1098 lm.AddDataSourceColumnReaders(colName, std::move(colReaders), typeID);
1099}
1100} // namespace
1101
1102void ROOT::Internal::RDF::AddDSColumns(const std::vector<std::string> &colNames, ROOT::Detail::RDF::RLoopManager &lm,
1104 const std::vector<const std::type_info *> &colTypeIDs,
1106{
1107 auto nCols = colNames.size();
1108 assert(nCols == colTypeIDs.size() && "Must provide exactly one column type for each column to create");
1109 for (decltype(nCols) i{}; i < nCols; i++) {
1110 AddDataSourceColumn(colNames[i], *colTypeIDs[i], lm, ds, colRegister);
1111 }
1112}
#define b(i)
Definition RSha256.hxx:100
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition TError.cxx:252
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 value
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:148
#define gROOT
Definition TROOT.h:417
externTVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define R__LOCKGUARD(mutex)
#define free
Definition civetweb.c:1578
The head node of a RDF computation graph.
void RegisterJitHelperCall(const std::string &funcBody, std::unique_ptr< ROOT::Internal::RDF::RColumnRegister > colRegister, const std::vector< std::string > &colnames, std::shared_ptr< void > jittedNode, std::shared_ptr< void > argument=nullptr)
const std::set< std::string > & GetSuppressErrorsForMissingBranches() const
void AddDataSourceColumnReaders(std::string_view col, std::vector< std::unique_ptr< RColumnReaderBase > > &&readers, const std::type_info &ti)
const ColumnNames_t & GetDefaultColumnNames() const
Return the list of default columns – empty if none was provided when constructing the RDataFrame.
bool HasDataSourceColumnReaders(std::string_view col, const std::type_info &ti) const
Return true if AddDataSourceColumnReaders was called for column name col.
A binder for user-defined columns, variations and aliases.
bool IsDefineOrAlias(std::string_view name) const
Check if the provided name is tracked in the names list.
bool IsAlias(std::string_view name) const
Return true if the given column name is an existing alias.
std::string_view ResolveAlias(std::string_view alias) const
Return the actual column name that the alias resolves to.
std::vector< std::string > GetVariationDeps(const std::string &column) const
Get the names of all variations that directly or indirectly affect a given column.
RDFDetail::RDefineBase * GetDefine(std::string_view colName) const
Return the RDefine for the requested column name, or nullptr.
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 const std::vector< std::string > & GetColumnNames() const =0
Returns a reference to the collection of the dataset's column names.
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:2994
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition TLeaf.h:57
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:124
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
Bool_t MatchB(const TString &s, const TString &mods="", Int_t start=0, Int_t nMaxMatch=10)
Definition TPRegexp.h:78
A TTree represents a columnar dataset.
Definition TTree.h:89
virtual TTree * GetTree() const
Definition TTree.h:604
const ColumnNames_t SelectColumns(unsigned int nRequiredNames, const ColumnNames_t &names, const ColumnNames_t &defaultNames)
Choose between local column names or default column names, throw in case of errors.
void CheckForNoVariations(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister)
Throw if the column has systematic variations attached.
ParsedTreePath ParseTreePath(std::string_view fullTreeName)
std::shared_ptr< RJittedDefine > BookDefinePerSampleJit(std::string_view name, std::string_view expression, RLoopManager &lm, const RColumnRegister &colRegister)
Book the jitting of a DefinePerSample call.
void CheckValidCppVarName(std::string_view var, const std::string &where)
void RemoveDuplicates(ColumnNames_t &columnNames)
ColumnNames_t GetValidatedColumnNames(RLoopManager &lm, const unsigned int nColumns, const ColumnNames_t &columns, const RColumnRegister &colRegister, RDataSource *ds)
Given the desired number of columns and the user-provided list of columns:
std::shared_ptr< RNodeBase > UpcastNode(std::shared_ptr< RNodeBase > ptr)
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:200
void CheckSnapshotOptionsFormatCompatibility(const ROOT::RDF::RSnapshotOptions &opts)
bool IsStrInVec(const std::string &str, const std::vector< std::string > &vec)
Definition RDFUtils.cxx:560
void CheckForDefinition(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister, const ColumnNames_t &dataSourceColumns)
Throw if column definedColView is not already there.
std::string PrettyPrintAddr(const void *const addr)
std::shared_ptr< RDFDetail::RJittedFilter > BookFilterJit(std::shared_ptr< RDFDetail::RNodeBase > prevNode, std::string_view name, std::string_view expression, const RColumnRegister &colRegister, TTree *tree, RDataSource *ds)
Book the jitting of a Filter call.
std::string JitBuildAction(const ColumnNames_t &cols, const std::type_info &helperArgType, const std::type_info &at, TTree *tree, const unsigned int nSlots, const RColumnRegister &colRegister, RDataSource *ds, const bool vector2RVec)
void CheckTypesAndPars(unsigned int nTemplateParams, unsigned int nColumnNames)
std::string DemangleTypeIdName(const std::type_info &typeInfo)
bool AtLeastOneEmptyString(const std::vector< std::string_view > strings)
std::unique_ptr< ROOT::Detail::RDF::RColumnReaderBase > CreateColumnReader(ROOT::RDF::RDataSource &ds, unsigned int slot, std::string_view col, const std::type_info &tid, TTreeReader *treeReader)
Definition RDFUtils.cxx:708
std::pair< std::vector< std::string >, std::vector< std::string > > AddSizeBranches(ROOT::RDF::RDataSource *ds, std::vector< std::string > &&colsWithoutAliases, std::vector< std::string > &&colsWithAliases)
Return copies of colsWithoutAliases and colsWithAliases with size branches for variable-sized array b...
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:339
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:272
void RemoveRNTupleSubfields(ColumnNames_t &columnNames)
bool IsInternalColumn(std::string_view colName)
Whether custom column with name colName is an "internal" column such as rdfentry_ or rdfslot_.
Definition RDFUtils.cxx:492
ColumnNames_t FilterArraySizeColNames(const ColumnNames_t &columnNames, const std::string &action)
Take a list of column names, return that list with entries starting by '#' filtered out.
void InterpreterDeclare(const std::string &code)
Declare code in the interpreter via the TInterpreter::Declare method, throw in case of errors.
Definition RDFUtils.cxx:443
std::vector< std::string > GetValidatedArgTypes(const ColumnNames_t &colNames, const RColumnRegister &colRegister, TTree *tree, RDataSource *ds, const std::string &context, bool vector2RVec)
void CheckForDuplicateSnapshotColumns(const ColumnNames_t &cols)
ColumnNames_t ConvertRegexToColumns(const ColumnNames_t &colNames, std::string_view columnNameRegexp, std::string_view callerName)
ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, const RColumnRegister &definedCols, const ColumnNames_t &dataSourceColumns)
void CheckForRedefinition(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister, const ColumnNames_t &dataSourceColumns)
Throw if column definedColView is already there.
std::shared_ptr< RJittedDefine > BookDefineJit(std::string_view name, std::string_view expression, RLoopManager &lm, RDataSource *ds, const RColumnRegister &colRegister)
Book the jitting of a Define call.
std::shared_ptr< RJittedVariation > BookVariationJit(const std::vector< std::string > &colNames, std::string_view variationName, const std::vector< std::string > &variationTags, std::string_view expression, RLoopManager &lm, RDataSource *ds, const RColumnRegister &colRegister, bool isSingleColumn, const std::string &varyColType)
Book the jitting of a Vary call.
std::vector< std::string > GetFilterNames()
Returns the names of the filters created.
std::vector< std::string > ColumnNames_t
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
A collection of options to steer the creation of the dataset on disk through Snapshot().
std::size_t fMaxUnzippedPageSize
(RNTuple only) Maximum allowed page size before compression
int fAutoFlush
(TTree only) AutoFlush value for output tree
ESnapshotOutputFormat fOutputFormat
Which data format to write to.
bool fEnableSamePageMerging
(RNTuple only) Enable identical-page deduplication. Requires page checksumming
std::size_t fInitialUnzippedPageSize
(RNTuple only) Initial page size before compression
bool fEnablePageChecksums
(RNTuple only) Enable checksumming for pages
std::size_t fApproxZippedClusterSize
(RNTuple only) Approximate target compressed cluster size
int fSplitLevel
(TTree only) Split level of output tree
std::size_t fMaxUnzippedClusterSize
(RNTuple only) Maximum uncompressed cluster size
int fBasketSize
(TTree only) Set a custom basket size option.