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 {
85std::pair<ColumnNames_t, ColumnNames_t> FindUsedColsAndAliases(
const std::string &expr,
86 const ROOT::Internal::RDF::RColumnRegister &colRegister,
87 const ColumnNames_t &dataSourceColNames)
89 lexertk::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 = lexertk::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 ==
".") {
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) {
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,
162 const ROOT::Internal::RDF::RColumnRegister &colRegister)
166 for (
const auto &alias : usedAliases) {
168 TPRegexp replacer(
"(?<!\\.)\\b" + EscapeDots(alias) +
"\\b");
169 replacer.Substitute(out, col.data(),
"g");
175ParsedExpression ParseRDFExpression(std::string_view expr,
const ROOT::Internal::RDF::RColumnRegister &colRegister,
176 const ColumnNames_t &dataSourceColNames)
179 TString preProcessedExpr(expr);
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");
187 std::tie(usedCols, usedAliases) =
188 FindUsedColsAndAliases(std::string(preProcessedExpr), colRegister, dataSourceColNames);
190 const auto exprNoAliases = ResolveAliases(preProcessedExpr, usedAliases, colRegister);
194 TString exprWithVars(exprNoAliases);
197 for (
auto i = 0u; i < varNames.size(); ++i)
198 varNames[i] =
"var" + std::to_string(i);
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");
213 return ParsedExpression{std::string(std::move(exprWithVars)), std::move(usedCols), std::move(varNames)};
223std::unordered_map<std::string, std::string> &GetJittedExprs() {
224 static std::unordered_map<std::string, std::string> jittedExpressions;
225 return jittedExpressions;
228std::string BuildFunctionString(
const std::string &expr,
const ColumnNames_t &vars,
const ColumnNames_t &varTypes,
229 bool isSingleColumn =
false,
const std::string &varyColType =
"")
231 assert(vars.size() == varTypes.size());
233 TPRegexp re(R
"(\breturn\b)");
234 const bool hasReturnStmt = re.MatchB(expr);
236 static const std::vector<std::string> fundamentalTypes = {
269 std::stringstream 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()) {
276 fullType =
"const " +
type +
" ";
280 fullType =
type +
"& ";
282 ss << fullType << vars[i] <<
", ";
285 ss.seekp(-2, ss.cur);
291 auto finalizeExprForVary = [&]() {
292 std::string trailRetType{};
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] ==
'}') {
302 trailRetType =
" -> ";
304 trailRetType +=
"ROOT::RVec<" + varyColType +
">";
306 trailRetType +=
"ROOT::RVec<ROOT::RVec<" + varyColType +
">>";
309 std::string trailRetToken{trailRetType.empty() ?
") {" :
')' + trailRetType +
'{'};
311 trailRetToken +=
" return ";
312 return trailRetToken;
315 if (!varyColType.empty())
316 ss << finalizeExprForVary();
318 ss << (hasReturnStmt ?
") {" :
") { return ");
321 ss << expr <<
"\n;}\n";
328std::string DeclareFunction(
const std::string &expr,
const ColumnNames_t &vars,
const ColumnNames_t &varTypes,
329 bool isSingleColumn =
false,
const std::string &varyColType =
"")
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()) {
338 const auto funcName = exprIt->second;
343 const auto funcBaseName =
"func" + std::to_string(exprMap.size());
344 const auto funcFullName =
"R_rdf::" + funcBaseName;
346 const auto toDeclare =
"namespace R_rdf {\nauto " + funcBaseName + funcCode +
"\nusing " + funcBaseName +
347 "_ret_t = typename ROOT::TypeTraits::CallableTraits<decltype(" + funcBaseName +
352 exprMap.insert({funcCode, funcFullName});
359std::string RetTypeOfFunc(
const std::string &funcName)
361 const auto dt =
gROOT->GetType((funcName +
"_ret_t").c_str());
363 const auto type = dt->GetFullTypeName();
368ThrowJitBuildActionHelperTypeError(
const std::string &actionTypeNameBase,
const std::type_info &helperArgType)
372 std::string actionHelperTypeName =
cname;
375 actionHelperTypeName = helperArgType.name();
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.";
386 throw std::runtime_error(exceptionText);
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);
411 if (!filteredColumns.empty()) {
412 std::string msg =
"Column name(s) {";
413 for (
auto &
c : filteredColumns)
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);
420 return columnListWithoutSizeColumns;
429 const char firstChar = var[0];
432 auto isALetter = [](
char c) {
return (
c >=
'A' &&
c <=
'Z') || (
c >=
'a' &&
c <=
'z'); };
433 const bool isValidFirstChar = firstChar ==
'_' || isALetter(firstChar);
434 if (!isValidFirstChar)
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)
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);
456 std::string tname(tn);
464 const auto theRegexSize = columnNameRegexp.size();
465 std::string theRegex(columnNameRegexp);
467 const auto isEmptyRegex = 0 == theRegexSize;
469 if (theRegexSize > 0 && theRegex[0] !=
'^')
470 theRegex =
"^" + theRegex;
471 if (theRegexSize > 0 && theRegex[theRegexSize - 1] !=
'$')
472 theRegex = theRegex +
"$";
479 for (
auto &&colName : colNames) {
481 selectedColumns.emplace_back(colName);
485 if (selectedColumns.empty()) {
486 std::string
text(callerName);
487 if (columnNameRegexp.empty()) {
488 text =
": there is no column available to match.";
490 text =
": regex \"" + std::string(columnNameRegexp) +
"\" did not match any column.";
492 throw std::runtime_error(
text);
494 return selectedColumns;
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.";
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())
510 "A column with that name is already present in the input data source. Use Redefine to force redefinition.";
512 if (!error.empty()) {
513 error =
"RDataFrame::" + where +
": cannot define column \"" + std::string(definedColView) +
"\". " + error;
514 throw std::runtime_error(error);
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.";
530 const bool isAlreadyDefined = colRegister.
IsDefineOrAlias(definedColView);
531 const bool isADSColumn =
532 std::find(dataSourceColumns.begin(), dataSourceColumns.end(), definedColView) != dataSourceColumns.end();
534 if (!isAlreadyDefined && !isADSColumn)
535 error =
"No column with that name was found in the dataset. Use Define to create a new column.";
538 if (!error.empty()) {
539 if (where ==
"DefaultValueFor")
540 error =
"RDataFrame::" + where +
": cannot provide default values for column \"" +
541 std::string(definedColView) +
"\". " + error;
543 error =
"RDataFrame::" + where +
": cannot redefine or vary column \"" + std::string(definedColView) +
"\". " +
545 throw std::runtime_error(error);
552 const std::string definedCol(definedColView);
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 \"" +
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);
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);
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);
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()));
597 return ColumnNames_t(defaultNames.begin(), defaultNames.begin() + nRequiredNames);
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") +
604 for (
const auto &
name : names)
605 msg +=
" \"" +
name +
"\",";
607 throw std::runtime_error(msg);
617 for (
auto &column : requiredCols) {
620 const auto isDataSourceColumn =
621 std::find(dataSourceColumns.begin(), dataSourceColumns.end(), column) != dataSourceColumns.end();
622 if (isDataSourceColumn)
624 unknownColumns.emplace_back(column);
626 return unknownColumns;
629std::vector<std::string>
GetFilterNames(
const std::shared_ptr<RLoopManager> &loopManager)
631 return loopManager->GetFiltersNames();
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());
644 return {std::string(treeName), std::string(dirName)};
651 s << std::hex << std::showbase << reinterpret_cast<size_t>(addr);
656std::shared_ptr<RDFDetail::RJittedFilter>
657BookFilterJit(std::shared_ptr<RDFDetail::RNodeBase> prevNode, std::string_view
name, std::string_view expression,
662 const auto parsedExpr = ParseRDFExpression(expression, colRegister, dsColumns);
663 const auto exprVarTypes =
665 const auto funcName = DeclareFunction(parsedExpr.fExpr, parsedExpr.fVarNames, exprVarTypes);
666 const auto type = RetTypeOfFunc(funcName);
668 throw std::runtime_error(
"Filter: the following expression does not evaluate to bool:\n" +
669 std::string(expression));
671 auto *lm = prevNode->GetLoopManagerUnchecked();
672 const auto jittedFilter = std::make_shared<RDFDetail::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 <<
", "
686 <<
"reinterpret_cast<ROOT::Detail::RDF::RJittedFilter*>(jittedFilter)"
688 lm->RegisterJitHelperCall(filterInvocation.str(),
689 std::make_unique<ROOT::Internal::RDF::RColumnRegister>(colRegister), parsedExpr.fUsedCols,
701 const auto parsedExpr = ParseRDFExpression(expression, colRegister, dsColumns);
702 const auto exprVarTypes =
704 const auto funcName = DeclareFunction(parsedExpr.fExpr, parsedExpr.fVarNames, exprVarTypes);
705 const auto type = RetTypeOfFunc(funcName);
707 auto jittedDefine = std::make_shared<RDFDetail::RJittedDefine>(
name,
type, lm, colRegister, parsedExpr.fUsedCols);
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>("
724 <<
"reinterpret_cast<ROOT::Detail::RDF::RJittedDefine *>(jittedDefine)"
726 lm.
RegisterJitHelperCall(defineInvocation.str(), std::make_unique<ROOT::Internal::RDF::RColumnRegister>(colRegister),
727 parsedExpr.fUsedCols, jittedDefine);
736 const auto funcName = DeclareFunction(std::string(expression), {
"rdfslot_",
"rdfsampleinfo_"},
737 {
"unsigned int",
"const ROOT::RDF::RSampleInfo"});
738 const auto retType = RetTypeOfFunc(funcName);
740 auto jittedDefine = std::make_shared<RDFDetail::RJittedDefine>(
name, retType, lm, colRegister,
ColumnNames_t{});
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>("
757 <<
"reinterpret_cast<ROOT::Detail::RDF::RJittedDefine *>(jittedDefine)"
759 lm.
RegisterJitHelperCall(defineInvocation.str(), std::make_unique<ROOT::Internal::RDF::RColumnRegister>(colRegister),
765std::shared_ptr<RJittedVariation>
767 const std::vector<std::string> &variationTags, std::string_view expression,
RLoopManager &lm,
769 const std::string &varyColType)
773 const auto parsedExpr = ParseRDFExpression(expression, colRegister, dsColumns);
774 const auto exprVarTypes =
776 const auto funcName =
777 DeclareFunction(parsedExpr.fExpr, parsedExpr.fVarNames, exprVarTypes, isSingleColumn, varyColType);
778 const auto type = RetTypeOfFunc(funcName);
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);
786 auto jittedVariation = std::make_shared<RJittedVariation>(colNames, variationName, variationTags,
type, colRegister,
787 lm, parsedExpr.fUsedCols);
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";
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
810 <<
"reinterpret_cast<ROOT::Internal::RDF::RJittedVariation *>(jittedVariation), "
811 <<
"(*variedColNamesAndTags)->first, "
812 <<
"(*variedColNamesAndTags)->second"
815 varyInvocation.str(), std::make_unique<ROOT::Internal::RDF::RColumnRegister>(colRegister), parsedExpr.fUsedCols,
817 std::make_shared<std::pair<std::vector<std::string>, std::vector<std::string>>>(colNames, variationTags));
818 return jittedVariation;
825 const bool vector2RVec)
829 if (!actionTypeClass) {
830 std::string exceptionText =
"An error occurred while inferring the action type of the operation.";
831 throw std::runtime_error(exceptionText);
833 const std::string actionTypeName = actionTypeClass->GetName();
834 const std::string actionTypeNameBase = actionTypeName.substr(actionTypeName.rfind(
':') + 1);
838 if (helperArgTypeName.empty()) {
839 ThrowJitBuildActionHelperTypeError(actionTypeNameBase, helperArgType);
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 <<
">("
858 <<
"reinterpret_cast<ROOT::Internal::RDF::RJittedAction *>(jittedAction), " << nSlots <<
", "
859 <<
"reinterpret_cast<std::shared_ptr<" << helperArgTypeName <<
"> *>(helperArg)"
861 return createAction_str.str();
866 for (
const auto &s : strings) {
873std::shared_ptr<RNodeBase>
UpcastNode(std::shared_ptr<RNodeBase> ptr)
888 for (
auto &col : selectedColumns) {
895 if (!unknownColumns.empty()) {
900 std::set<std::string> intersection;
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);
910 throw std::runtime_error(errMsg);
914 return selectedColumns;
921 auto toCheckedArgType = [&](
const std::string &
c) {
922 RDFDetail::RDefineBase *define = colRegister.
GetDefine(
c);
924 if (colType.rfind(
"CLING_UNKNOWN_TYPE", 0) == 0) {
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);
933 std::vector<std::string> colTypes;
934 colTypes.reserve(colNames.size());
935 std::transform(colNames.begin(), colNames.end(), std::back_inserter(colTypes), toCheckedArgType);
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);
955 std::string optionName;
960 optionName =
"fApproxZippedClusterSize";
962 optionName =
"fMaxUnzippedClusterSize";
964 optionName =
"fInitialUnzippedPageSize";
966 optionName =
"fMaxUnzippedPageSize";
968 optionName =
"fEnablePageChecksums";
970 optionName =
"fEnableSamePageMerging";
973 if (!optionName.empty()) {
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.",
983 optionName =
"fAutoFlush";
985 optionName =
"fSplitLevel";
987 optionName =
"fBasketSize";
990 if (!optionName.empty()) {
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.",
1003std::pair<std::vector<std::string>, std::vector<std::string>>
1005 std::vector<std::string> &&colsWithAliases)
1011 return {std::move(colsWithoutAliases), std::move(colsWithAliases)};
1013 assert(colsWithoutAliases.size() == colsWithAliases.size());
1015 auto nCols = colsWithoutAliases.size();
1017 for (std::size_t i = 0u; i < nCols; ++i) {
1018 const auto &colName = colsWithoutAliases[i];
1020 auto *
b = tree->GetBranch(colName.c_str());
1022 b = tree->FindBranch(colName.c_str());
1027 auto *leaves =
b->GetListOfLeaves();
1036 colsWithoutAliases.insert(colsWithoutAliases.begin() + i, countLeaf->
GetName());
1037 colsWithAliases.insert(colsWithAliases.begin() + i, countLeaf->
GetName());
1042 return {std::move(colsWithoutAliases), std::move(colsWithAliases)};
1047 std::set<std::string> uniqueCols;
1049 std::remove_if(columnNames.begin(), columnNames.end(),
1050 [&uniqueCols](
const std::string &colName) { return !uniqueCols.insert(colName).second; }),
1058 std::copy_if(columnNames.cbegin(), columnNames.cend(), std::back_inserter(parentFields),
1059 [](
const std::string &colName) { return colName.find(
'.') == std::string::npos; });
1061 columnNames.erase(std::remove_if(columnNames.begin(), columnNames.end(),
1062 [&parentFields](
const std::string &colName) {
1063 if (colName.find(
'.') == std::string::npos)
1065 const auto parentFieldName = colName.substr(0, colName.find_first_of(
'.'));
1066 return std::find(parentFields.cbegin(), parentFields.cend(), parentFieldName) !=
1091 std::vector<std::unique_ptr<ROOT::Detail::RDF::RColumnReaderBase>> colReaders;
1092 colReaders.reserve(nSlots);
1094 for (
auto slot = 0u; slot < nSlots; ++slot)
1095 colReaders.emplace_back(
1104 const std::vector<const std::type_info *> &colTypeIDs,
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);
#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
externTVirtualMutex * gROOTMutex
#define R__LOCKGUARD(mutex)
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.
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.
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 * 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.
virtual TLeaf * GetLeafCount() const
If this leaf stores a variable-sized array or a multi-dimensional array whose last dimension has vari...
const char * GetName() const override
Returns name of object.
Bool_t MatchB(const TString &s, const TString &mods="", Int_t start=0, Int_t nMaxMatch=10)
A TTree represents a columnar dataset.
virtual TTree * GetTree() const
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...
void CheckSnapshotOptionsFormatCompatibility(const ROOT::RDF::RSnapshotOptions &opts)
bool IsStrInVec(const std::string &str, const std::vector< std::string > &vec)
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)
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.
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.
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_.
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.
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)
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.