32 #pragma GCC diagnostic push
33 #pragma GCC diagnostic ignored "-Woverloaded-virtual"
34 #pragma GCC diagnostic ignored "-Wshadow"
36 #include "lexertk.hpp"
38 #pragma GCC diagnostic pop
50 class RCustomColumnBase;
70 std::set<std::string> GetPotentialColumnNames(
const std::string &expr)
72 lexertk::generator generator;
73 const auto ok = generator.process(expr);
75 const auto msg =
"Failed to tokenize expression:\n" + expr +
"\n\nMake sure it is valid C++.";
76 throw std::runtime_error(msg);
79 std::set<std::string> potCols;
80 const auto nToks = generator.size();
81 std::string potColWithDots;
83 auto IsSymbol = [](
const lexertk::token &t) {
return t.type == lexertk::token::e_symbol; };
84 auto IsDot = [](
const lexertk::token &t) {
return t.value ==
"."; };
87 for (
auto i = 0ULL; i < nToks; ++i) {
88 auto &tok = generator[i];
92 if (i == 0 || (i > 0 && !IsDot(generator[i - 1])))
93 potCols.insert(tok.value);
99 potColWithDots = tok.value;
103 auto &nextTok = generator[i + 1];
104 auto &next2nextTok = generator[i + 2];
105 if (!IsDot(nextTok) || !IsSymbol(next2nextTok)) {
108 potColWithDots +=
"." + next2nextTok.value;
109 potCols.insert(potColWithDots);
121 HeadNode_t CreateSnapshotRDF(
const ColumnNames_t &validCols,
122 std::string_view treeName,
123 std::string_view fileName,
125 RLoopManager &loopManager,
126 std::unique_ptr<RDFInternal::RActionBase> actionPtr)
129 ::TDirectory::TContext ctxt;
130 auto snapshotRDF = std::make_shared<ROOT::RDataFrame>(treeName, fileName, validCols);
131 auto snapshotRDFResPtr = MakeResultPtr(snapshotRDF, loopManager, std::move(actionPtr));
136 return snapshotRDFResPtr;
139 std::string DemangleTypeIdName(
const std::type_info &typeInfo)
142 return TClassEdit::DemangleTypeIdName(typeInfo, dummy);
145 ColumnNames_t ConvertRegexToColumns(
const RDFInternal::RBookedCustomColumns & customColumns,
147 ROOT::RDF::RDataSource *dataSource,
148 std::string_view columnNameRegexp,
149 std::string_view callerName)
151 const auto theRegexSize = columnNameRegexp.size();
152 std::string theRegex(columnNameRegexp);
154 const auto isEmptyRegex = 0 == theRegexSize;
156 if (theRegexSize > 0 && theRegex[0] !=
'^')
157 theRegex =
"^" + theRegex;
158 if (theRegexSize > 0 && theRegex[theRegexSize - 1] !=
'$')
159 theRegex = theRegex +
"$";
161 ColumnNames_t selectedColumns;
162 selectedColumns.reserve(32);
166 TPRegexp regexp(theRegex);
167 for (
auto &&branchName : customColumns.GetNames()) {
168 if ((isEmptyRegex || 0 != regexp.Match(branchName.c_str())) &&
169 !RDFInternal::IsInternalColumn(branchName)) {
170 selectedColumns.emplace_back(branchName);
175 auto branchNames = RDFInternal::GetTopLevelBranchNames(*tree);
176 for (
auto &branchName : branchNames) {
177 if (isEmptyRegex || 0 != regexp.Match(branchName.c_str())) {
178 selectedColumns.emplace_back(branchName);
184 auto &dsColNames = dataSource->GetColumnNames();
185 for (
auto &dsColName : dsColNames) {
186 if ((isEmptyRegex || 0 != regexp.Match(dsColName.c_str())) &&
187 !RDFInternal::IsInternalColumn(dsColName)) {
188 selectedColumns.emplace_back(dsColName);
193 if (selectedColumns.empty()) {
194 std::string text(callerName);
195 if (columnNameRegexp.empty()) {
196 text =
": there is no column available to match.";
198 text =
": regex \"" + std::string(columnNameRegexp) +
"\" did not match any column.";
200 throw std::runtime_error(text);
202 return selectedColumns;
205 void GetTopLevelBranchNamesImpl(TTree &t, std::set<std::string> &bNamesReg, ColumnNames_t &bNames,
206 std::set<TTree *> &analysedTrees)
209 if (!analysedTrees.insert(&t).second) {
213 auto branches = t.GetListOfBranches();
215 for (
auto branchObj : *branches) {
216 auto name = branchObj->GetName();
217 if (bNamesReg.insert(name).second) {
218 bNames.emplace_back(name);
223 auto friendTrees = t.GetListOfFriends();
228 for (
auto friendTreeObj : *friendTrees) {
229 auto friendTree = ((TFriendElement *)friendTreeObj)->GetTree();
230 GetTopLevelBranchNamesImpl(*friendTree, bNamesReg, bNames, analysedTrees);
236 ColumnNames_t GetTopLevelBranchNames(TTree &t)
238 std::set<std::string> bNamesSet;
239 ColumnNames_t bNames;
240 std::set<TTree *> analysedTrees;
241 GetTopLevelBranchNamesImpl(t, bNamesSet, bNames, analysedTrees);
245 bool IsValidCppVarName(
const std::string &var)
249 const char firstChar = var[0];
252 auto isALetter = [](
char c) {
return (c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z'); };
253 const bool isValidFirstChar = firstChar ==
'_' || isALetter(firstChar);
254 if (!isValidFirstChar)
258 auto isANumber = [](
char c) {
return c >=
'0' && c <=
'9'; };
259 auto isValidTok = [&isALetter, &isANumber](
char c) {
return c ==
'_' || isALetter(c) || isANumber(c); };
260 for (
const char c : var)
267 void CheckCustomColumn(std::string_view definedCol, TTree *treePtr,
const ColumnNames_t &customCols,
268 const std::map<std::string, std::string> &aliasMap,
const ColumnNames_t &dataSourceColumns)
270 const std::string definedColStr(definedCol);
272 if (!IsValidCppVarName(definedColStr)) {
273 const auto msg =
"Cannot define column \"" + definedColStr +
"\": not a valid C++ variable name.";
274 throw std::runtime_error(msg);
277 if (treePtr !=
nullptr) {
279 const auto branch = treePtr->GetBranch(definedColStr.c_str());
280 if (branch !=
nullptr) {
281 const auto msg =
"branch \"" + definedColStr +
"\" already present in TTree";
282 throw std::runtime_error(msg);
286 if (std::find(customCols.begin(), customCols.end(), definedCol) != customCols.end()) {
287 const auto msg =
"Redefinition of column \"" + definedColStr +
"\"";
288 throw std::runtime_error(msg);
292 const auto aliasColNameIt = aliasMap.find(definedColStr);
293 if (aliasColNameIt != aliasMap.end()) {
294 const auto msg =
"An alias with name " + definedColStr +
" pointing to column " +
295 aliasColNameIt->second +
" is already existing.";
296 throw std::runtime_error(msg);
300 if (!dataSourceColumns.empty()) {
301 if (std::find(dataSourceColumns.begin(), dataSourceColumns.end(), definedCol) != dataSourceColumns.end()) {
302 const auto msg =
"Redefinition of column \"" + definedColStr +
"\" already present in the data-source";
303 throw std::runtime_error(msg);
308 void CheckTypesAndPars(
unsigned int nTemplateParams,
unsigned int nColumnNames)
310 if (nTemplateParams != nColumnNames) {
311 std::string err_msg =
"The number of template parameters specified is ";
312 err_msg += std::to_string(nTemplateParams);
313 err_msg +=
" while ";
314 err_msg += std::to_string(nColumnNames);
315 err_msg +=
" columns have been specified.";
316 throw std::runtime_error(err_msg);
322 SelectColumns(
unsigned int nRequiredNames,
const ColumnNames_t &names,
const ColumnNames_t &defaultNames)
326 if (defaultNames.size() < nRequiredNames)
327 throw std::runtime_error(
328 std::to_string(nRequiredNames) +
" column name" + (nRequiredNames == 1 ?
" is" :
"s are") +
329 " required but none were provided and the default list has size " + std::to_string(defaultNames.size()));
331 return ColumnNames_t(defaultNames.begin(), defaultNames.begin() + nRequiredNames);
334 if (names.size() != nRequiredNames) {
335 auto msg = std::to_string(nRequiredNames) +
" column name" + (nRequiredNames == 1 ?
" is" :
"s are") +
336 " required but " + std::to_string(names.size()) + (names.size() == 1 ?
" was" :
" were") +
338 for (
const auto &name : names)
339 msg +=
" \"" + name +
"\",";
341 throw std::runtime_error(msg);
347 ColumnNames_t FindUnknownColumns(
const ColumnNames_t &requiredCols,
const ColumnNames_t &datasetColumns,
348 const ColumnNames_t &definedCols,
const ColumnNames_t &dataSourceColumns)
350 ColumnNames_t unknownColumns;
351 for (
auto &column : requiredCols) {
352 const auto isBranch = std::find(datasetColumns.begin(), datasetColumns.end(), column) != datasetColumns.end();
355 const auto isCustomColumn = std::find(definedCols.begin(), definedCols.end(), column) != definedCols.end();
358 const auto isDataSourceColumn =
359 std::find(dataSourceColumns.begin(), dataSourceColumns.end(), column) != dataSourceColumns.end();
360 if (isDataSourceColumn)
362 unknownColumns.emplace_back(column);
364 return unknownColumns;
367 bool IsInternalColumn(std::string_view colName)
369 const auto str = colName.data();
370 const auto goodPrefix = colName.size() > 3 &&
371 (
'r' == str[0] ||
't' == str[0]) &&
372 0 == strncmp(
"df", str + 1, 2);
373 return goodPrefix &&
'_' == colName.back();
376 std::vector<std::string> GetFilterNames(
const std::shared_ptr<RLoopManager> &loopManager)
378 return loopManager->GetFiltersNames();
382 unsigned int Replace(std::string &s,
const std::string what,
const std::string withWhat)
385 auto numReplacements = 0U;
386 while ((idx = s.find(what, idx)) != std::string::npos) {
387 s.replace(idx, what.size(), withWhat);
388 idx += withWhat.size();
391 return numReplacements;
396 std::vector<std::string> FindUsedColumnNames(std::string_view expression, ColumnNames_t branches,
397 const ColumnNames_t &customColumns,
const ColumnNames_t &dsColumns,
398 const std::map<std::string, std::string> &aliasMap)
401 const auto potCols = GetPotentialColumnNames(std::string(expression));
403 if (potCols.size() == 0)
return {};
405 std::set<std::string> usedBranches;
408 for (
auto &brName : customColumns) {
409 if (potCols.find(brName) != potCols.end()) {
410 usedBranches.insert(brName);
422 std::sort(branches.begin(), branches.end(),
423 [](
const std::string &s0,
const std::string &s1) {
return s0 > s1;});
425 for (
auto &brName : branches) {
427 if (potCols.find(brName) == potCols.end()) {
432 auto isContained = [&brName](
const std::string &usedBr) {
437 return usedBr.find(brName) != std::string::npos &&
438 std::count(usedBr.begin(), usedBr.end(),
'.') > std::count(brName.begin(), brName.end(),
'.');
440 auto it = std::find_if(usedBranches.begin(), usedBranches.end(), isContained);
441 if (it == usedBranches.end()) {
442 usedBranches.insert(brName);
447 for (
auto &col : dsColumns) {
448 if (potCols.find(col) != potCols.end()) {
449 usedBranches.insert(col);
454 for (
auto &alias_colName : aliasMap) {
455 auto &alias = alias_colName.first;
456 if (potCols.find(alias) != potCols.end()) {
457 usedBranches.insert(alias);
461 return std::vector<std::string>(usedBranches.begin(), usedBranches.end());
465 std::vector<std::string> ReplaceDots(
const ColumnNames_t &colNames)
467 std::vector<std::string> dotlessNames = colNames;
468 for (
auto &c : dotlessNames) {
469 const bool hasDot = c.find_first_of(
'.') != std::string::npos;
471 std::replace(c.begin(), c.end(),
'.',
'_');
472 c.insert(0u,
"__rdf_arg_");
479 std::vector<std::string> ColumnTypesAsString(ColumnNames_t &colNames, ColumnNames_t &varNames,
480 const std::map<std::string, std::string> &aliasMap, TTree *tree,
481 RDataSource *ds, std::string &expr,
unsigned int namespaceID,
482 const RDFInternal::RBookedCustomColumns &customCols)
484 std::vector<std::string> colTypes;
485 colTypes.reserve(colNames.size());
486 const auto aliasMapEnd = aliasMap.end();
488 for (
auto c = colNames.begin(), v = varNames.begin(); c != colNames.end();) {
489 const auto &colName = *c;
491 if (colName.find(
'.') != std::string::npos) {
493 auto numRepl = Replace(expr, colName, *v);
498 c = colNames.erase(c);
499 v = varNames.erase(v);
505 const auto paddedExpr =
" " + expr +
" ";
506 static const std::string noWordChars(
"[^a-zA-Z0-9_]");
507 const auto colNameRxBody = noWordChars + colName + noWordChars;
508 TRegexp colNameRegex(colNameRxBody.c_str());
510 const auto colStillThere = colNameRegex.Index(paddedExpr.c_str(), &matchedLen) != -1;
511 if (!colStillThere) {
512 c = colNames.erase(c);
513 v = varNames.erase(v);
520 const auto aliasMapIt = aliasMap.find(colName);
521 const auto &realColName = aliasMapEnd == aliasMapIt ? colName : aliasMapIt->second;
523 const auto isCustomCol = customCols.HasName(realColName);
524 const auto customColID = isCustomCol ? customCols.GetColumns().at(realColName)->GetID() : 0;
525 const auto colTypeName =
526 ColumnName2ColumnTypeName(realColName, namespaceID, tree, ds, isCustomCol,
true, customColID);
527 colTypes.emplace_back(colTypeName);
536 void TryToJitExpression(
const std::string &expression,
const ColumnNames_t &colNames,
537 const std::vector<std::string> &colTypes,
bool hasReturnStmt)
539 R__ASSERT(colNames.size() == colTypes.size());
541 static unsigned int iNs = 0U;
542 std::stringstream dummyDecl;
543 dummyDecl <<
"namespace __rdf_" << std::to_string(iNs++) <<
"{ auto rdf_f = []() {";
545 for (
auto col = colNames.begin(), type = colTypes.begin(); col != colNames.end(); ++col, ++type) {
546 dummyDecl << *type <<
" " << *col <<
";\n";
552 dummyDecl << expression <<
"\n;};}";
554 dummyDecl <<
"return " << expression <<
"\n;};}";
557 if (!gInterpreter->Declare(dummyDecl.str().c_str())) {
559 "Cannot interpret the following expression:\n" + std::string(expression) +
"\n\nMake sure it is valid C++.";
560 throw std::runtime_error(msg);
565 BuildLambdaString(
const std::string &expr,
const ColumnNames_t &vars,
const ColumnNames_t &varTypes,
bool hasReturnStmt)
567 R__ASSERT(vars.size() == varTypes.size());
569 std::stringstream ss;
571 for (
auto i = 0u; i < vars.size(); ++i) {
574 ss << varTypes[i] <<
"& " << vars[i] <<
", ";
577 ss.seekp(-2, ss.cur);
583 ss << expr <<
"\n;}";
588 std::string PrettyPrintAddr(
const void *
const addr)
592 s << std::hex << std::showbase << reinterpret_cast<size_t>(addr);
599 void BookFilterJit(RJittedFilter *jittedFilter,
void *prevNodeOnHeap, std::string_view name,
600 std::string_view expression,
const std::map<std::string, std::string> &aliasMap,
601 const ColumnNames_t &branches,
const RDFInternal::RBookedCustomColumns &customCols, TTree *tree,
602 RDataSource *ds,
unsigned int namespaceID)
604 const auto &dsColumns = ds ? ds->GetColumnNames() : ColumnNames_t{};
607 auto usedBranches = FindUsedColumnNames(expression, branches, customCols.GetNames(), dsColumns, aliasMap);
608 auto varNames = ReplaceDots(usedBranches);
609 auto dotlessExpr = std::string(expression);
610 const auto usedColTypes =
611 ColumnTypesAsString(usedBranches, varNames, aliasMap, tree, ds, dotlessExpr, namespaceID, customCols);
613 TRegexp re(
"[^a-zA-Z0-9_]?return[^a-zA-Z0-9_]");
615 const bool hasReturnStmt = re.Index(dotlessExpr, &matchedLen) != -1;
617 auto lm = jittedFilter->GetLoopManagerUnchecked();
618 lm->JitDeclarations();
619 TryToJitExpression(dotlessExpr, varNames, usedColTypes, hasReturnStmt);
621 const auto filterLambda = BuildLambdaString(dotlessExpr, varNames, usedColTypes, hasReturnStmt);
623 const auto jittedFilterAddr = PrettyPrintAddr(jittedFilter);
624 const auto prevNodeAddr = PrettyPrintAddr(prevNodeOnHeap);
627 ROOT::Internal::RDF::RBookedCustomColumns *columnsOnHeap =
new ROOT::Internal::RDF::RBookedCustomColumns(customCols);
628 const auto columnsOnHeapAddr = PrettyPrintAddr(columnsOnHeap);
632 std::stringstream filterInvocation;
633 filterInvocation <<
"ROOT::Internal::RDF::JitFilterHelper(" << filterLambda <<
", {";
634 for (
const auto &brName : usedBranches) {
636 const auto aliasMapIt = aliasMap.find(brName);
637 auto &realBrName = aliasMapIt == aliasMap.end() ? brName : aliasMapIt->second;
638 filterInvocation <<
"\"" << realBrName <<
"\", ";
640 if (!usedBranches.empty())
641 filterInvocation.seekp(-2, filterInvocation.cur);
642 filterInvocation <<
"}, \"" << name <<
"\", "
643 <<
"reinterpret_cast<ROOT::Detail::RDF::RJittedFilter*>(" << jittedFilterAddr <<
"), "
644 <<
"reinterpret_cast<std::shared_ptr<ROOT::Detail::RDF::RNodeBase>*>(" << prevNodeAddr <<
"),"
645 <<
"reinterpret_cast<ROOT::Internal::RDF::RBookedCustomColumns*>(" << columnsOnHeapAddr <<
")"
648 lm->ToJitExec(filterInvocation.str());
652 void BookDefineJit(std::string_view name, std::string_view expression, RLoopManager &lm, RDataSource *ds,
653 const std::shared_ptr<RJittedCustomColumn> &jittedCustomColumn,
654 const RDFInternal::RBookedCustomColumns &customCols,
const ColumnNames_t &branches)
656 const auto &aliasMap = lm.GetAliasMap();
657 auto *
const tree = lm.GetTree();
658 const auto namespaceID = lm.GetID();
659 const auto &dsColumns = ds ? ds->GetColumnNames() : ColumnNames_t{};
662 auto usedBranches = FindUsedColumnNames(expression, branches, customCols.GetNames(), dsColumns, aliasMap);
663 auto varNames = ReplaceDots(usedBranches);
664 auto dotlessExpr = std::string(expression);
665 const auto usedColTypes =
666 ColumnTypesAsString(usedBranches, varNames, aliasMap, tree, ds, dotlessExpr, namespaceID, customCols);
668 TRegexp re(
"[^a-zA-Z0-9_]?return[^a-zA-Z0-9_]");
670 const bool hasReturnStmt = re.Index(dotlessExpr, &matchedLen) != -1;
672 lm.JitDeclarations();
673 TryToJitExpression(dotlessExpr, varNames, usedColTypes, hasReturnStmt);
675 const auto definelambda = BuildLambdaString(dotlessExpr, varNames, usedColTypes, hasReturnStmt);
676 const auto customColID = std::to_string(jittedCustomColumn->GetID());
677 const auto lambdaName =
"eval_" + std::string(name) + customColID;
678 const auto ns =
"__rdf" + std::to_string(namespaceID);
680 auto customColumnsCopy =
new RDFInternal::RBookedCustomColumns(customCols);
681 auto customColumnsAddr = PrettyPrintAddr(customColumnsCopy);
686 const auto defineDeclaration =
687 "namespace " + ns +
" { auto " + lambdaName +
" = " + definelambda +
";\n" +
"using " + std::string(name) +
688 customColID +
"_type = typename ROOT::TypeTraits::CallableTraits<decltype(" + lambdaName +
" )>::ret_type; }\n";
689 lm.ToJitDeclare(defineDeclaration);
691 std::stringstream defineInvocation;
692 defineInvocation <<
"ROOT::Internal::RDF::JitDefineHelper(" << definelambda <<
", {";
693 for (
auto brName : usedBranches) {
695 auto aliasMapIt = aliasMap.find(brName);
696 auto &realBrName = aliasMapIt == aliasMap.end() ? brName : aliasMapIt->second;
697 defineInvocation <<
"\"" << realBrName <<
"\", ";
699 if (!usedBranches.empty())
700 defineInvocation.seekp(-2, defineInvocation.cur);
701 defineInvocation <<
"}, \"" << name <<
"\", reinterpret_cast<ROOT::Detail::RDF::RLoopManager*>("
702 << PrettyPrintAddr(&lm) <<
"), *reinterpret_cast<ROOT::Detail::RDF::RJittedCustomColumn*>("
703 << PrettyPrintAddr(jittedCustomColumn.get()) <<
"),"
704 <<
"reinterpret_cast<ROOT::Internal::RDF::RBookedCustomColumns*>(" << customColumnsAddr <<
")"
707 lm.ToJitExec(defineInvocation.str());
712 std::string JitBuildAction(
const ColumnNames_t &bl,
void *prevNode,
const std::type_info &art,
const std::type_info &at,
713 void *rOnHeap, TTree *tree,
const unsigned int nSlots,
714 const RDFInternal::RBookedCustomColumns &customCols, RDataSource *ds,
715 std::shared_ptr<RJittedAction> *jittedActionOnHeap,
unsigned int namespaceID)
717 auto nBranches = bl.size();
720 std::vector<std::string> columnTypeNames(nBranches);
721 for (
auto i = 0u; i < nBranches; ++i) {
722 const auto isCustomCol = customCols.HasName(bl[i]);
723 const auto customColID = isCustomCol ? customCols.GetColumns().at(bl[i])->GetID() : 0;
724 const auto columnTypeName =
725 ColumnName2ColumnTypeName(bl[i], namespaceID, tree, ds, isCustomCol,
true, customColID);
726 if (columnTypeName.empty()) {
727 std::string exceptionText =
"The type of column ";
728 exceptionText += bl[i];
729 exceptionText +=
" could not be guessed. Please specify one.";
730 throw std::runtime_error(exceptionText.c_str());
732 columnTypeNames[i] = columnTypeName;
736 auto actionResultTypeClass = TClass::GetClass(art);
737 if (!actionResultTypeClass) {
738 std::string exceptionText =
"An error occurred while inferring the result type of an operation.";
739 throw std::runtime_error(exceptionText.c_str());
741 const auto actionResultTypeName = actionResultTypeClass->GetName();
744 auto actionTypeClass = TClass::GetClass(at);
745 if (!actionTypeClass) {
746 std::string exceptionText =
"An error occurred while inferring the action type of the operation.";
747 throw std::runtime_error(exceptionText.c_str());
749 const auto actionTypeName = actionTypeClass->GetName();
751 auto customColumnsCopy =
new RDFInternal::RBookedCustomColumns(customCols);
752 auto customColumnsAddr = PrettyPrintAddr(customColumnsCopy);
756 std::stringstream createAction_str;
757 createAction_str <<
"ROOT::Internal::RDF::CallBuildAction"
758 <<
"<" << actionTypeName;
759 for (
auto &colType : columnTypeNames)
760 createAction_str <<
", " << colType;
763 createAction_str <<
">(reinterpret_cast<std::shared_ptr<ROOT::Detail::RDF::RNodeBase>*>("
764 << PrettyPrintAddr(prevNode) <<
"), {";
765 for (
auto i = 0u; i < bl.size(); ++i) {
767 createAction_str <<
", ";
768 createAction_str <<
'"' << bl[i] <<
'"';
770 createAction_str <<
"}, " << std::dec << std::noshowbase << nSlots <<
", reinterpret_cast<" << actionResultTypeName
771 <<
"*>(" << PrettyPrintAddr(rOnHeap) <<
")"
772 <<
", reinterpret_cast<std::shared_ptr<ROOT::Internal::RDF::RJittedAction>*>("
773 << PrettyPrintAddr(jittedActionOnHeap) <<
"),"
774 <<
"reinterpret_cast<ROOT::Internal::RDF::RBookedCustomColumns*>(" << customColumnsAddr <<
")"
776 return createAction_str.str();
779 bool AtLeastOneEmptyString(
const std::vector<std::string_view> strings)
781 for (
const auto &s : strings) {
788 std::shared_ptr<RNodeBase> UpcastNode(std::shared_ptr<RNodeBase> ptr)
797 ColumnNames_t GetValidatedColumnNames(RLoopManager &lm,
const unsigned int nColumns,
const ColumnNames_t &columns,
798 const ColumnNames_t &validCustomColumns, RDataSource *ds)
800 const auto &defaultColumns = lm.GetDefaultColumnNames();
801 auto selectedColumns = SelectColumns(nColumns, columns, defaultColumns);
802 const auto &validBranchNames = lm.GetBranchNames();
803 const auto unknownColumns = FindUnknownColumns(selectedColumns, validBranchNames, validCustomColumns,
804 ds ? ds->GetColumnNames() : ColumnNames_t{});
806 if (!unknownColumns.empty()) {
808 std::stringstream unknowns;
809 std::string delim = unknownColumns.size() > 1 ?
"s: " :
": ";
810 for (
auto &unknownColumn : unknownColumns) {
811 unknowns << delim << unknownColumn;
814 throw std::runtime_error(
"Unknown column" + unknowns.str());
818 auto &aliasMap = lm.GetAliasMap();
819 auto aliasMapEnd = aliasMap.end();
821 for (
auto idx : ROOT::TSeqU(selectedColumns.size())) {
822 const auto &colName = selectedColumns[idx];
823 const auto aliasColumnNameIt = aliasMap.find(colName);
824 if (aliasMapEnd != aliasColumnNameIt) {
825 selectedColumns[idx] = aliasColumnNameIt->second;
829 return selectedColumns;
835 std::vector<bool> FindUndefinedDSColumns(
const ColumnNames_t &requestedCols,
const ColumnNames_t &definedCols)
837 const auto nColumns = requestedCols.size();
838 std::vector<bool> mustBeDefined(nColumns,
false);
839 for (
auto i = 0u; i < nColumns; ++i)
840 mustBeDefined[i] = std::find(definedCols.begin(), definedCols.end(), requestedCols[i]) == definedCols.end();
841 return mustBeDefined;