40#pragma GCC diagnostic push
41#pragma GCC diagnostic ignored "-Woverloaded-virtual"
42#pragma GCC diagnostic ignored "-Wshadow"
46#pragma GCC diagnostic pop
60#include <unordered_map>
61#include <unordered_set>
74struct ParsedExpression {
79 ColumnNames_t fUsedCols;
81 ColumnNames_t fVarNames;
85std::pair<ColumnNames_t, ColumnNames_t> FindUsedColsAndAliases(
const std::string &expr,
87 const ColumnNames_t &dataSourceColNames)
89 exprtk::lexer::generator tokens;
90 const auto tokensOk = tokens.process(expr);
92 const auto msg =
"Failed to tokenize expression:\n" + expr +
"\n\nMake sure it is valid C++.";
93 throw std::runtime_error(msg);
96 std::unordered_set<std::string> usedCols;
97 std::unordered_set<std::string> usedAliases;
100 const auto nTokens = tokens.size();
101 const auto kSymbol = exprtk::lexer::token::e_symbol;
102 for (
auto i = 0u; i < nTokens; ++i) {
103 const auto &tok = tokens[i];
105 if (tok.type != kSymbol || tok.value ==
"&" || tok.value ==
"|") {
112 if (i > 0 && tokens[i - 1].
value ==
".") {
116 ColumnNames_t potentialColNames({tok.value});
119 auto dotChainKeepsGoing = [&](
unsigned int _i) {
120 return _i + 2 <= nTokens && tokens[_i + 1].value ==
"." && tokens[_i + 2].type == kSymbol;
122 while (dotChainKeepsGoing(i)) {
123 potentialColNames.emplace_back(potentialColNames.back() +
"." + tokens[i + 2].value);
129 const auto maybeAnAlias = potentialColNames[0];
130 const auto &resolvedAlias = colRegister.
ResolveAlias(maybeAnAlias);
131 if (resolvedAlias != maybeAnAlias) {
132 usedAliases.insert(maybeAnAlias);
133 for (
auto &s : potentialColNames)
134 s.replace(0, maybeAnAlias.
size(), resolvedAlias);
139 auto isRDFColumn = [&](
const std::string &col) {
140 if (colRegister.
IsDefineOrAlias(col) || IsStrInVec(col, dataSourceColNames))
144 const auto longestRDFColMatch = std::find_if(potentialColNames.crbegin(), potentialColNames.crend(), isRDFColumn);
145 if (longestRDFColMatch != potentialColNames.crend())
146 usedCols.insert(*longestRDFColMatch);
149 return {{usedCols.begin(), usedCols.end()}, {usedAliases.begin(), usedAliases.end()}};
153std::string EscapeDots(
const std::string &s)
157 dot.Substitute(out,
"\\.",
"g");
158 return std::string(std::move(out));
161TString ResolveAliases(
const TString &expr,
const ColumnNames_t &usedAliases,
166 for (
const auto &alias : usedAliases) {
168 TPRegexp replacer(
"(?<!\\.)\\b" + EscapeDots(alias) +
"\\b");
169 replacer.Substitute(out, col.data(),
"g");
176 const ColumnNames_t &dataSourceColNames)
179 TString preProcessedExpr(expr);
193 R
"REGEX(#(?!(ifdef|ifndef|if|else|elif|endif|pragma|define|undef|include|line))([a-zA-Z_][a-zA-Z0-9_]*)(?=(?:[^"]*"[^"]*")*[^"]*$))REGEX");
194 colSizeReplacer.Substitute(preProcessedExpr, "R_rdf_sizeof_$2",
"g");
196 ColumnNames_t usedCols;
197 ColumnNames_t usedAliases;
198 std::tie(usedCols, usedAliases) =
199 FindUsedColsAndAliases(std::string(preProcessedExpr), colRegister, dataSourceColNames);
201 const auto exprNoAliases = ResolveAliases(preProcessedExpr, usedAliases, colRegister);
205 TString exprWithVars(exprNoAliases);
207 ColumnNames_t varNames(usedCols.size());
208 for (
auto i = 0u; i < varNames.size(); ++i)
209 varNames[i] =
"var" + std::to_string(i);
216 std::sort(usedCols.begin(), usedCols.end(),
217 [](
const std::string &
a,
const std::string &
b) { return a.size() > b.size(); });
218 for (
const auto &col : usedCols) {
219 const auto varIdx = std::distance(usedCols.begin(), std::find(usedCols.begin(), usedCols.end(), col));
220 TPRegexp replacer(
"(?<!\\.)\\b" + EscapeDots(col) +
"\\b");
221 replacer.Substitute(exprWithVars, varNames[varIdx],
"g");
224 return ParsedExpression{std::string(std::move(exprWithVars)), std::move(usedCols), std::move(varNames)};
234std::unordered_map<std::string, std::string> &GetJittedExprs() {
235 static std::unordered_map<std::string, std::string> jittedExpressions;
236 return jittedExpressions;
239std::string BuildFunctionString(
const std::string &expr,
const ColumnNames_t &vars,
const ColumnNames_t &varTypes,
240 bool isSingleColumn =
false,
const std::string &varyColType =
"")
242 assert(vars.size() == varTypes.size());
245 const bool hasReturnStmt = re.MatchB(expr);
247 static const std::vector<std::string> fundamentalTypes = {
280 std::stringstream ss;
282 for (
auto i = 0u; i < vars.size(); ++i) {
283 std::string fullType;
284 const auto &
type = varTypes[i];
285 if (std::find(fundamentalTypes.begin(), fundamentalTypes.end(),
type) != fundamentalTypes.end()) {
287 fullType =
"const " +
type +
" ";
291 fullType =
type +
"& ";
293 ss << fullType << vars[i] <<
", ";
296 ss.seekp(-2, ss.cur);
302 auto finalizeExprForVary = [&]() {
303 std::string trailRetType{};
305 auto first_not_space = expr.find_first_not_of(
" \n\t");
306 auto last_not_space = expr.find_last_not_of(
" \n\t");
307 if (first_not_space != std::string::npos && last_not_space != std::string::npos && expr[first_not_space] ==
'{' &&
308 expr[last_not_space] ==
'}') {
313 trailRetType =
" -> ";
315 trailRetType +=
"ROOT::RVec<" + varyColType +
">";
317 trailRetType +=
"ROOT::RVec<ROOT::RVec<" + varyColType +
">>";
320 std::string trailRetToken{trailRetType.empty() ?
") {" :
')' + trailRetType +
'{'};
322 trailRetToken +=
" return ";
323 return trailRetToken;
326 if (!varyColType.empty())
327 ss << finalizeExprForVary();
329 ss << (hasReturnStmt ?
") {" :
") { return ");
332 ss << expr <<
"\n;}\n";
339std::string DeclareFunction(
const std::string &expr,
const ColumnNames_t &vars,
const ColumnNames_t &varTypes,
340 bool isSingleColumn =
false,
const std::string &varyColType =
"")
344 const auto funcCode = BuildFunctionString(expr, vars, varTypes, isSingleColumn, varyColType);
345 auto &exprMap = GetJittedExprs();
346 const auto exprIt = exprMap.find(funcCode);
347 if (exprIt != exprMap.end()) {
349 const auto funcName = exprIt->second;
354 const auto funcBaseName =
"func" + std::to_string(exprMap.size());
355 const auto funcFullName =
"R_rdf::" + funcBaseName;
357 const auto toDeclare =
"namespace R_rdf {\nauto " + funcBaseName + funcCode +
"\nusing " + funcBaseName +
358 "_ret_t = typename ROOT::TypeTraits::CallableTraits<decltype(" + funcBaseName +
363 exprMap.insert({funcCode, funcFullName});
370std::string RetTypeOfFunc(
const std::string &funcName)
372 const auto dt =
gROOT->GetType((funcName +
"_ret_t").c_str());
374 const auto type = dt->GetFullTypeName();
379ThrowJitBuildActionHelperTypeError(
const std::string &actionTypeNameBase,
const std::type_info &helperArgType)
383 std::string actionHelperTypeName =
cname;
386 actionHelperTypeName = helperArgType.name();
388 std::string exceptionText =
389 "RDataFrame::Jit: cannot just-in-time compile a \"" + actionTypeNameBase +
"\" action using helper type \"" +
390 actionHelperTypeName +
391 "\". This typically happens in a custom `Fill` or `Book` invocation where the types of the input columns have "
392 "not been specified as template parameters and the ROOT interpreter has no knowledge of this type of action "
393 "helper. Please add template parameters for the types of the input columns to avoid jitting this action (i.e. "
394 "`df.Fill<float>(..., {\"x\"})`, where `float` is the type of `x`) or declare the action helper type to the "
395 "interpreter, e.g. via gInterpreter->Declare.";
397 throw std::runtime_error(exceptionText);
408ColumnNames_t FilterArraySizeColNames(
const ColumnNames_t &columnNames,
const std::string &action)
410 ColumnNames_t columnListWithoutSizeColumns;
411 ColumnNames_t filteredColumns;
412 std::copy_if(columnNames.begin(), columnNames.end(), std::back_inserter(columnListWithoutSizeColumns),
413 [&](
const std::string &
name) {
414 if (name[0] ==
'#') {
415 filteredColumns.emplace_back(name);
422 if (!filteredColumns.empty()) {
423 std::string msg =
"Column name(s) {";
424 for (
auto &
c : filteredColumns)
426 msg[msg.size() - 2] =
'}';
427 msg +=
"will be ignored. Please go through a valid Alias to " + action +
" an array size column";
428 throw std::runtime_error(msg);
431 return columnListWithoutSizeColumns;
434void CheckValidCppVarName(std::string_view var,
const std::string &where)
440 const char firstChar = var[0];
443 auto isALetter = [](
char c) {
return (
c >=
'A' &&
c <=
'Z') || (
c >=
'a' &&
c <=
'z'); };
444 const bool isValidFirstChar = firstChar ==
'_' || isALetter(firstChar);
445 if (!isValidFirstChar)
449 auto isANumber = [](
char c) {
return c >=
'0' &&
c <=
'9'; };
450 auto isValidTok = [&isALetter, &isANumber](
char c) {
return c ==
'_' || isALetter(
c) || isANumber(
c); };
451 for (
const char c : var)
456 const auto objName = where ==
"Define" ?
"column" : (where ==
"Alias" ?
"alias" :
"variation");
457 const auto error =
"RDataFrame::" + where +
": cannot define " + objName +
" \"" + std::string(var) +
458 "\". Not a valid C++ variable name.";
459 throw std::runtime_error(error);
467 std::string tname(tn);
473ConvertRegexToColumns(
const ColumnNames_t &colNames, std::string_view columnNameRegexp, std::string_view callerName)
475 const auto theRegexSize = columnNameRegexp.size();
476 std::string theRegex(columnNameRegexp);
478 const auto isEmptyRegex = 0 == theRegexSize;
480 if (theRegexSize > 0 && theRegex[0] !=
'^')
481 theRegex =
"^" + theRegex;
482 if (theRegexSize > 0 && theRegex[theRegexSize - 1] !=
'$')
483 theRegex = theRegex +
"$";
485 ColumnNames_t selectedColumns;
490 for (
auto &&colName : colNames) {
491 if ((isEmptyRegex || regexp.MatchB(colName.c_str())) && !
IsInternalColumn(colName)) {
492 selectedColumns.emplace_back(colName);
496 if (selectedColumns.empty()) {
497 std::string
text(callerName);
498 if (columnNameRegexp.empty()) {
499 text =
": there is no column available to match.";
501 text =
": regex \"" + std::string(columnNameRegexp) +
"\" did not match any column.";
503 throw std::runtime_error(
text);
505 return selectedColumns;
509void CheckForRedefinition(
const std::string &where, std::string_view definedColView,
const RColumnRegister &colRegister,
510 const ColumnNames_t &dataSourceColumns)
514 if (colRegister.IsAlias(definedColView))
515 error =
"An alias with that name, pointing to column \"" + std::string(colRegister.ResolveAlias(definedColView)) +
516 "\", already exists in this branch of the computation graph.";
517 else if (colRegister.IsDefineOrAlias(definedColView))
518 error =
"A column with that name has already been Define'd. Use Redefine to force redefinition.";
519 else if (std::find(dataSourceColumns.begin(), dataSourceColumns.end(), definedColView) != dataSourceColumns.end())
521 "A column with that name is already present in the input data source. Use Redefine to force redefinition.";
523 if (!error.empty()) {
524 error =
"RDataFrame::" + where +
": cannot define column \"" + std::string(definedColView) +
"\". " + error;
525 throw std::runtime_error(error);
530void CheckForDefinition(
const std::string &where, std::string_view definedColView,
const RColumnRegister &colRegister,
531 const ColumnNames_t &dataSourceColumns)
535 if (colRegister.IsAlias(definedColView)) {
536 error =
"An alias with that name, pointing to column \"" + std::string(colRegister.ResolveAlias(definedColView)) +
537 "\", already exists. Aliases cannot be Redefined or Varied.";
541 const bool isAlreadyDefined = colRegister.IsDefineOrAlias(definedColView);
542 const bool isADSColumn =
543 std::find(dataSourceColumns.begin(), dataSourceColumns.end(), definedColView) != dataSourceColumns.end();
545 if (!isAlreadyDefined && !isADSColumn)
546 error =
"No column with that name was found in the dataset. Use Define to create a new column.";
549 if (!error.empty()) {
550 if (where ==
"DefaultValueFor")
551 error =
"RDataFrame::" + where +
": cannot provide default values for column \"" +
552 std::string(definedColView) +
"\". " + error;
554 error =
"RDataFrame::" + where +
": cannot redefine or vary column \"" + std::string(definedColView) +
"\". " +
556 throw std::runtime_error(error);
561void CheckForNoVariations(
const std::string &where, std::string_view definedColView,
const RColumnRegister &colRegister)
563 const std::string definedCol(definedColView);
564 const auto &variationDeps = colRegister.GetVariationDeps(definedCol);
565 if (!variationDeps.empty()) {
566 if (where ==
"Redefine") {
567 const std::string error =
"RDataFrame::" + where +
": cannot redefine column \"" + definedCol +
568 "\". The column depends on one or more systematic variations and re-defining varied "
569 "columns is not supported.";
570 throw std::runtime_error(error);
571 }
else if (where ==
"DefaultValueFor") {
572 const std::string error =
"RDataFrame::" + where +
": cannot provide a default value for column \"" +
574 "\". The column depends on one or more systematic variations and it should not be "
575 "possible to have missing values in varied columns.";
576 throw std::runtime_error(error);
578 const std::string error =
579 "RDataFrame::" + where +
": this operation cannot work with columns that depend on systematic variations.";
580 throw std::runtime_error(error);
585void CheckTypesAndPars(
unsigned int nTemplateParams,
unsigned int nColumnNames)
587 if (nTemplateParams != nColumnNames) {
588 std::string err_msg =
"The number of template parameters specified is ";
589 err_msg += std::to_string(nTemplateParams);
590 err_msg +=
" while ";
591 err_msg += std::to_string(nColumnNames);
592 err_msg +=
" columns have been specified.";
593 throw std::runtime_error(err_msg);
599SelectColumns(
unsigned int nRequiredNames,
const ColumnNames_t &names,
const ColumnNames_t &defaultNames)
603 if (defaultNames.size() < nRequiredNames)
604 throw std::runtime_error(
605 std::to_string(nRequiredNames) +
" column name" + (nRequiredNames == 1 ?
" is" :
"s are") +
606 " required but none were provided and the default list has size " + std::to_string(defaultNames.
size()));
608 return ColumnNames_t(defaultNames.begin(), defaultNames.begin() + nRequiredNames);
611 if (names.size() != nRequiredNames) {
612 auto msg = std::to_string(nRequiredNames) +
" column name" + (nRequiredNames == 1 ?
" is" :
"s are") +
613 " required but " + std::to_string(names.size()) + (names.size() == 1 ?
" was" :
" were") +
615 for (
const auto &
name : names)
616 msg +=
" \"" +
name +
"\",";
618 throw std::runtime_error(msg);
624ColumnNames_t FindUnknownColumns(
const ColumnNames_t &requiredCols,
const RColumnRegister &definedCols,
625 const ColumnNames_t &dataSourceColumns)
627 ColumnNames_t unknownColumns;
628 for (
auto &column : requiredCols) {
629 if (definedCols.IsDefineOrAlias(column))
631 const auto isDataSourceColumn =
632 std::find(dataSourceColumns.begin(), dataSourceColumns.end(), column) != dataSourceColumns.end();
633 if (isDataSourceColumn)
635 unknownColumns.emplace_back(column);
637 return unknownColumns;
640std::vector<std::string> GetFilterNames(
const std::shared_ptr<RLoopManager> &loopManager)
642 return loopManager->GetFiltersNames();
645ParsedTreePath ParseTreePath(std::string_view fullTreeName)
648 std::string_view dirName =
"";
649 std::string_view treeName = fullTreeName;
650 const auto lastSlash = fullTreeName.rfind(
'/');
651 if (std::string_view::npos != lastSlash) {
652 dirName = treeName.substr(0, lastSlash);
653 treeName = treeName.substr(lastSlash + 1, treeName.size());
655 return {std::string(treeName), std::string(dirName)};
662 s << std::hex << std::showbase << reinterpret_cast<size_t>(addr);
667std::shared_ptr<RDFDetail::RJittedFilter>
668BookFilterJit(std::shared_ptr<RDFDetail::RNodeBase> prevNode, std::string_view
name, std::string_view expression,
669 const RColumnRegister &colRegister,
TTree *tree, RDataSource *ds)
671 const auto &dsColumns = ds ? ds->GetColumnNames() : ColumnNames_t{};
673 const auto parsedExpr = ParseRDFExpression(expression, colRegister, dsColumns);
674 const auto exprVarTypes =
675 GetValidatedArgTypes(parsedExpr.fUsedCols, colRegister, tree, ds,
"Filter",
true);
676 const auto funcName = DeclareFunction(parsedExpr.fExpr, parsedExpr.fVarNames, exprVarTypes);
677 const auto type = RetTypeOfFunc(funcName);
679 throw std::runtime_error(
"Filter: the following expression does not evaluate to bool:\n" +
680 std::string(expression));
682 auto *lm = prevNode->GetLoopManagerUnchecked();
683 const auto jittedFilter = std::make_shared<RDFDetail::RJittedFilter>(
684 lm,
name,
Union(colRegister.GetVariationDeps(parsedExpr.fUsedCols), prevNode->GetVariations()), prevNode);
687 std::stringstream filterInvocation;
688 filterInvocation <<
"(const std::vector<std::string> &colNames, "
689 <<
"ROOT::Internal::RDF::RColumnRegister &colRegister, "
690 <<
"ROOT::Detail::RDF::RLoopManager &lm, "
691 <<
"void *jittedFilter, "
692 <<
"std::shared_ptr<void> *) {\n";
693 filterInvocation <<
" ROOT::Internal::RDF::JitFilterHelper(" << funcName <<
", "
697 <<
"reinterpret_cast<ROOT::Detail::RDF::RJittedFilter*>(jittedFilter)"
699 lm->RegisterJitHelperCall(filterInvocation.str(),
700 std::make_unique<ROOT::Internal::RDF::RColumnRegister>(colRegister), parsedExpr.fUsedCols,
707std::shared_ptr<RJittedDefine> BookDefineJit(std::string_view
name, std::string_view expression, RLoopManager &lm,
708 RDataSource *ds,
const RColumnRegister &colRegister)
710 const auto &dsColumns = ds ? ds->GetColumnNames() : ColumnNames_t{};
712 const auto parsedExpr = ParseRDFExpression(expression, colRegister, dsColumns);
713 const auto exprVarTypes =
714 GetValidatedArgTypes(parsedExpr.fUsedCols, colRegister,
nullptr, ds,
"Define",
true);
715 const auto funcName = DeclareFunction(parsedExpr.fExpr, parsedExpr.fVarNames, exprVarTypes);
716 const auto type = RetTypeOfFunc(funcName);
718 auto jittedDefine = std::make_shared<RDFDetail::RJittedDefine>(
name,
type, lm, colRegister, parsedExpr.fUsedCols);
724 std::stringstream defineInvocation;
725 defineInvocation <<
"(const std::vector<std::string> &colNames, "
726 <<
"ROOT::Internal::RDF::RColumnRegister &colRegister, "
727 <<
"ROOT::Detail::RDF::RLoopManager &lm, "
728 <<
"void *jittedDefine, "
729 <<
"std::shared_ptr<void> *) {\n";
730 defineInvocation <<
" ROOT::Internal::RDF::JitDefineHelper<ROOT::Internal::RDF::DefineTypes::RDefineTag>("
735 <<
"reinterpret_cast<ROOT::Detail::RDF::RJittedDefine *>(jittedDefine)"
737 lm.RegisterJitHelperCall(defineInvocation.str(), std::make_unique<ROOT::Internal::RDF::RColumnRegister>(colRegister),
738 parsedExpr.fUsedCols, jittedDefine);
744std::shared_ptr<RJittedDefine> BookDefinePerSampleJit(std::string_view
name, std::string_view expression,
745 RLoopManager &lm,
const RColumnRegister &colRegister)
747 const auto funcName = DeclareFunction(std::string(expression), {
"rdfslot_",
"rdfsampleinfo_"},
748 {
"unsigned int",
"const ROOT::RDF::RSampleInfo"});
749 const auto retType = RetTypeOfFunc(funcName);
751 auto jittedDefine = std::make_shared<RDFDetail::RJittedDefine>(
name, retType, lm, colRegister, ColumnNames_t{});
757 std::stringstream defineInvocation;
758 defineInvocation <<
"(const std::vector<std::string> &colNames, "
759 <<
"ROOT::Internal::RDF::RColumnRegister &colRegister, "
760 <<
"ROOT::Detail::RDF::RLoopManager &lm, "
761 <<
"void *jittedDefine, "
762 <<
"std::shared_ptr<void> *) {\n";
763 defineInvocation <<
" ROOT::Internal::RDF::JitDefineHelper<ROOT::Internal::RDF::DefineTypes::RDefinePerSampleTag>("
768 <<
"reinterpret_cast<ROOT::Detail::RDF::RJittedDefine *>(jittedDefine)"
770 lm.RegisterJitHelperCall(defineInvocation.str(), std::make_unique<ROOT::Internal::RDF::RColumnRegister>(colRegister),
776std::shared_ptr<RJittedVariation>
777BookVariationJit(
const std::vector<std::string> &colNames, std::string_view variationName,
778 const std::vector<std::string> &variationTags, std::string_view expression, RLoopManager &lm,
779 RDataSource *ds,
const RColumnRegister &colRegister,
bool isSingleColumn,
780 const std::string &varyColType)
782 const auto &dsColumns = ds ? ds->GetColumnNames() : ColumnNames_t{};
784 const auto parsedExpr = ParseRDFExpression(expression, colRegister, dsColumns);
785 const auto exprVarTypes =
786 GetValidatedArgTypes(parsedExpr.fUsedCols, colRegister,
nullptr, ds,
"Vary",
true);
787 const auto funcName =
788 DeclareFunction(parsedExpr.fExpr, parsedExpr.fVarNames, exprVarTypes, isSingleColumn, varyColType);
789 const auto type = RetTypeOfFunc(funcName);
791 if (
type.rfind(
"ROOT::VecOps::RVec", 0) != 0) {
792 throw std::runtime_error(
793 "Jitted Vary expressions must return an RVec object. The following expression return type is '" +
type +
794 "' instead:\n" + parsedExpr.fExpr);
797 auto jittedVariation = std::make_shared<RJittedVariation>(colNames, variationName, variationTags,
type, colRegister,
798 lm, parsedExpr.fUsedCols);
807 std::stringstream varyInvocation;
808 varyInvocation <<
"(const std::vector<std::string> &inputColNames, "
809 <<
"ROOT::Internal::RDF::RColumnRegister &colRegister, "
810 <<
"ROOT::Detail::RDF::RLoopManager &lm, "
811 <<
"void *jittedVariation, "
812 <<
"std::shared_ptr<void> *helperArg) {\n";
814 <<
" auto *variedColNamesAndTags = reinterpret_cast<std::shared_ptr<std::pair<std::vector<std::string>, "
815 "std::vector<std::string>>> *>(helperArg);"
816 <<
" ROOT::Internal::RDF::JitVariationHelper<" << (isSingleColumn ?
"true" :
"false") <<
">(" << funcName
821 <<
"reinterpret_cast<ROOT::Internal::RDF::RJittedVariation *>(jittedVariation), "
822 <<
"(*variedColNamesAndTags)->first, "
823 <<
"(*variedColNamesAndTags)->second"
825 lm.RegisterJitHelperCall(
826 varyInvocation.str(), std::make_unique<ROOT::Internal::RDF::RColumnRegister>(colRegister), parsedExpr.fUsedCols,
828 std::make_shared<std::pair<std::vector<std::string>, std::vector<std::string>>>(colNames, variationTags));
829 return jittedVariation;
834std::string JitBuildAction(
const ColumnNames_t &cols,
const std::type_info &helperArgType,
const std::type_info &at,
835 TTree *tree,
const unsigned int nSlots,
const RColumnRegister &colRegister, RDataSource *ds,
836 const bool vector2RVec)
840 if (!actionTypeClass) {
841 std::string exceptionText =
"An error occurred while inferring the action type of the operation.";
842 throw std::runtime_error(exceptionText);
844 const std::string actionTypeName = actionTypeClass->GetName();
845 const std::string actionTypeNameBase = actionTypeName.substr(actionTypeName.rfind(
':') + 1);
849 if (helperArgTypeName.empty()) {
850 ThrowJitBuildActionHelperTypeError(actionTypeNameBase, helperArgType);
855 std::stringstream createAction_str;
856 createAction_str <<
"(const std::vector<std::string> &colNames, "
857 <<
"ROOT::Internal::RDF::RColumnRegister &colRegister, "
858 <<
"ROOT::Detail::RDF::RLoopManager &lm, "
859 <<
"void *jittedAction, "
860 <<
"std::shared_ptr<void> *helperArg) {\n";
861 createAction_str <<
" ROOT::Internal::RDF::CallBuildAction<" << actionTypeName;
862 const auto columnTypeNames = GetValidatedArgTypes(cols, colRegister, tree, ds, actionTypeNameBase, vector2RVec);
863 for (
auto &colType : columnTypeNames)
864 createAction_str <<
", " << colType;
865 createAction_str <<
">("
869 <<
"reinterpret_cast<ROOT::Internal::RDF::RJittedAction *>(jittedAction), " << nSlots <<
", "
870 <<
"reinterpret_cast<std::shared_ptr<" << helperArgTypeName <<
"> *>(helperArg)"
872 return createAction_str.str();
875bool AtLeastOneEmptyString(
const std::vector<std::string_view> strings)
877 for (
const auto &s : strings) {
884std::shared_ptr<RNodeBase> UpcastNode(std::shared_ptr<RNodeBase> ptr)
894ColumnNames_t GetValidatedColumnNames(RLoopManager &lm,
const unsigned int nColumns,
const ColumnNames_t &columns,
895 const RColumnRegister &colRegister, RDataSource *ds)
897 auto selectedColumns = SelectColumns(nColumns, columns, lm.GetDefaultColumnNames());
899 for (
auto &col : selectedColumns) {
900 col = colRegister.ResolveAlias(col);
904 auto unknownColumns = FindUnknownColumns(selectedColumns, colRegister, ds ? ds->GetColumnNames() : ColumnNames_t{});
906 if (!unknownColumns.empty()) {
911 std::set<std::string> intersection;
912 const auto &colsToIgnore = lm.GetSuppressErrorsForMissingBranches();
913 std::sort(unknownColumns.begin(), unknownColumns.end());
914 std::set_intersection(unknownColumns.cbegin(), unknownColumns.cend(), colsToIgnore.cbegin(), colsToIgnore.cend(),
915 std::inserter(intersection, intersection.begin()));
916 if (intersection.empty()) {
917 std::string errMsg = std::string(
"Unknown column") + (unknownColumns.size() > 1 ?
"s: " :
": ");
918 for (
auto &unknownColumn : unknownColumns)
919 errMsg +=
'"' + unknownColumn +
"\", ";
920 errMsg.resize(errMsg.size() - 2);
921 throw std::runtime_error(errMsg);
925 return selectedColumns;
928std::vector<std::string> GetValidatedArgTypes(
const ColumnNames_t &colNames,
const RColumnRegister &colRegister,
929 TTree *tree, RDataSource *ds,
const std::string &context,
932 auto toCheckedArgType = [&](
const std::string &
c) {
935 if (colType.rfind(
"CLING_UNKNOWN_TYPE", 0) == 0) {
937 "The type of custom column \"" +
c +
"\" (" + colType.substr(19) +
938 ") is not known to the interpreter, but a just-in-time-compiled " + context +
939 " call requires this column. Make sure to create and load ROOT dictionaries for this column's class.";
940 throw std::runtime_error(msg);
944 std::vector<std::string> colTypes;
945 colTypes.reserve(colNames.size());
946 std::transform(colNames.begin(), colNames.end(), std::back_inserter(colTypes), toCheckedArgType);
950void CheckForDuplicateSnapshotColumns(
const ColumnNames_t &cols)
952 std::unordered_set<std::string> uniqueCols;
953 for (
auto &col : cols) {
954 if (!uniqueCols.insert(col).second) {
955 const auto msg =
"Error: column \"" + col +
956 "\" was passed to Snapshot twice. This is not supported: only one of the columns would be "
957 "readable with RDataFrame.";
958 throw std::logic_error(msg);
966 std::string optionName;
971 optionName =
"fApproxZippedClusterSize";
973 optionName =
"fMaxUnzippedClusterSize";
975 optionName =
"fInitialUnzippedPageSize";
977 optionName =
"fMaxUnzippedPageSize";
979 optionName =
"fEnablePageChecksums";
981 optionName =
"fEnableSamePageMerging";
984 if (!optionName.empty()) {
986 "The RNTuple-specific %s option in RSnapshotOptions has been set, but the output format is "
987 "set to TTree, so this option won't have any effect. Use the other options available in "
988 "RSnapshotOptions to "
989 "configure the output TTree. Alternatively, change fOutputFormat to snapshot to RNTuple instead.",
994 optionName =
"fAutoFlush";
996 optionName =
"fSplitLevel";
998 optionName =
"fBasketSize";
1001 if (!optionName.empty()) {
1004 "The TTree-specific %s option in RSnapshotOptions has been set, but the output format is set to RNTuple, "
1005 "so this option won't have any effect. Use the fNTupleWriteOptions option available in RSnapshotOptions to "
1006 "configure the output RNTuple. Alternatively, change fOutputFormat to snapshot to TTree instead.",
1007 optionName.c_str());
1014std::pair<std::vector<std::string>, std::vector<std::string>>
1016 std::vector<std::string> &&colsWithAliases)
1022 return {std::move(colsWithoutAliases), std::move(colsWithAliases)};
1024 assert(colsWithoutAliases.size() == colsWithAliases.size());
1026 auto nCols = colsWithoutAliases.size();
1028 for (std::size_t i = 0u; i < nCols; ++i) {
1029 const auto &colName = colsWithoutAliases[i];
1042 TLeaf *countLeaf =
static_cast<TLeaf *
>(leaves->At(0))->GetLeafCount();
1043 if (!countLeaf || IsStrInVec(countLeaf->
GetName(), colsWithoutAliases))
1047 colsWithoutAliases.insert(colsWithoutAliases.begin() + i, countLeaf->
GetName());
1048 colsWithAliases.insert(colsWithAliases.begin() + i, countLeaf->
GetName());
1053 return {std::move(colsWithoutAliases), std::move(colsWithAliases)};
1056void RemoveDuplicates(ColumnNames_t &columnNames)
1058 std::set<std::string> uniqueCols;
1060 std::remove_if(columnNames.begin(), columnNames.end(),
1061 [&uniqueCols](
const std::string &colName) { return !uniqueCols.insert(colName).second; }),
1065void RemoveRNTupleSubfields(ColumnNames_t &columnNames)
1067 ColumnNames_t parentFields;
1069 std::copy_if(columnNames.cbegin(), columnNames.cend(), std::back_inserter(parentFields),
1070 [](
const std::string &colName) { return colName.find(
'.') == std::string::npos; });
1072 columnNames.erase(std::remove_if(columnNames.begin(), columnNames.end(),
1073 [&parentFields](
const std::string &colName) {
1074 if (colName.find(
'.') == std::string::npos)
1076 const auto parentFieldName = colName.substr(0, colName.find_first_of(
'.'));
1077 return std::find(parentFields.cbegin(), parentFields.cend(), parentFieldName) !=
1102 std::vector<std::unique_ptr<ROOT::Detail::RDF::RColumnReaderBase>> colReaders;
1103 colReaders.reserve(nSlots);
1105 for (
auto slot = 0u; slot < nSlots; ++slot)
1106 colReaders.emplace_back(
1115 const std::vector<const std::type_info *> &colTypeIDs,
1118 auto nCols = colNames.size();
1119 assert(nCols == colTypeIDs.size() &&
"Must provide exactly one column type for each column to create");
1120 for (
decltype(nCols) i{}; i < nCols; i++) {
1121 AddDataSourceColumn(colNames[i], *colTypeIDs[i], lm, ds, colRegister);
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
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
R__EXTERN TVirtualMutex * gROOTMutex
#define R__LOCKGUARD(mutex)
The head node of a RDF computation graph.
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)
unsigned int GetNSlots() const
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.
std::string_view ResolveAlias(std::string_view alias) const
Return the actual column name that the alias resolves to.
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.
TObjArray * GetListOfLeaves()
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.
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
const char * GetName() const override
Returns name of object.
A TTree represents a columnar dataset.
virtual TBranch * FindBranch(const char *name)
Return the branch that correspond to the path 'branchname', which can include the name of the tree or...
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
virtual TTree * GetTree() const
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...
bool IsStrInVec(const std::string &str, const std::vector< std::string > &vec)
std::string PrettyPrintAddr(const void *const addr)
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)
std::string ColumnName2ColumnTypeName(const std::string &colName, TTree *, RDataSource *, RDefineBase *, bool vector2RVec=true)
Return a string containing the type of the given branch.
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.
bool IsInternalColumn(std::string_view colName)
Whether custom column with name colName is an "internal" column such as rdfentry_ or rdfslot_.
void InterpreterDeclare(const std::string &code)
Declare code in the interpreter via the TInterpreter::Declare method, throw in case of errors.
std::vector< std::string > ColumnNames_t
char * DemangleTypeIdName(const std::type_info &ti, int &errorCode)
Demangle in a portable way the type id name.
if(fPos !=fText.size()) Fail("unexpected trailing content")
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.