Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/root/ROOT/RDF/InterfaceUtils.hxx was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 // Author: Enrico Guiraud, Danilo Piparo CERN  02/2018
0002 
0003 /*************************************************************************
0004  * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers.               *
0005  * All rights reserved.                                                  *
0006  *                                                                       *
0007  * For the licensing terms see $ROOTSYS/LICENSE.                         *
0008  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
0009  *************************************************************************/
0010 
0011 #ifndef ROOT_RDF_TINTERFACE_UTILS
0012 #define ROOT_RDF_TINTERFACE_UTILS
0013 
0014 #include <ROOT/RDF/RAction.hxx>
0015 #include <ROOT/RDF/RActionSnapshot.hxx>
0016 #include <ROOT/RDF/ActionHelpers.hxx> // for BuildAction
0017 #include <ROOT/RDF/SnapshotHelpers.hxx>
0018 #include <ROOT/RDF/RColumnRegister.hxx>
0019 #include <ROOT/RDF/RDefine.hxx>
0020 #include <ROOT/RDF/RDefinePerSample.hxx>
0021 #include <ROOT/RDF/RFilter.hxx>
0022 #include <ROOT/RDF/Utils.hxx>
0023 #include <ROOT/RDF/RJittedAction.hxx>
0024 #include <ROOT/RDF/RJittedDefine.hxx>
0025 #include <ROOT/RDF/RJittedFilter.hxx>
0026 #include <ROOT/RDF/RJittedVariation.hxx>
0027 #include <ROOT/RDF/RLoopManager.hxx>
0028 #include <string_view>
0029 #include <ROOT/RDF/RVariation.hxx>
0030 #include <ROOT/TypeTraits.hxx>
0031 #include <RConfigure.h> // for R__HAS_ROOT7
0032 #include <TError.h> // gErrorIgnoreLevel
0033 #include <TH1.h>
0034 #include <TROOT.h> // IsImplicitMTEnabled
0035 
0036 #include <deque>
0037 #include <functional>
0038 #include <list>
0039 #include <memory>
0040 #include <string>
0041 #include <type_traits>
0042 #include <typeinfo>
0043 #include <vector>
0044 
0045 class TTree;
0046 namespace ROOT {
0047 namespace Detail {
0048 namespace RDF {
0049 class RNodeBase;
0050 }
0051 }
0052 namespace RDF {
0053 template <typename Proxied>
0054 class RInterface;
0055 using RNode = RInterface<::ROOT::Detail::RDF::RNodeBase>;
0056 } // namespace RDF
0057 
0058 } // namespace ROOT
0059 
0060 /// \cond HIDDEN_SYMBOLS
0061 
0062 namespace ROOT {
0063 namespace Internal {
0064 namespace RDF {
0065 using namespace ROOT::Detail::RDF;
0066 using namespace ROOT::RDF;
0067 namespace TTraits = ROOT::TypeTraits;
0068 
0069 std::string DemangleTypeIdName(const std::type_info &typeInfo);
0070 
0071 ColumnNames_t
0072 ConvertRegexToColumns(const ColumnNames_t &colNames, std::string_view columnNameRegexp, std::string_view callerName);
0073 
0074 /// An helper object that sets and resets gErrorIgnoreLevel via RAII.
0075 class RIgnoreErrorLevelRAII {
0076 private:
0077    int fCurIgnoreErrorLevel = gErrorIgnoreLevel;
0078 
0079 public:
0080    RIgnoreErrorLevelRAII(int errorIgnoreLevel) { gErrorIgnoreLevel = errorIgnoreLevel; }
0081    ~RIgnoreErrorLevelRAII() { gErrorIgnoreLevel = fCurIgnoreErrorLevel; }
0082 };
0083 
0084 /****** BuildAction overloads *******/
0085 
0086 // clang-format off
0087 /// This namespace defines types to be used for tag dispatching in RInterface.
0088 namespace ActionTags {
0089 struct Histo1D{};
0090 struct Histo2D{};
0091 struct Histo3D{};
0092 struct HistoND{};
0093 struct HistoNSparseD{};
0094 struct Hist{};
0095 struct HistWithWeight{};
0096 struct Graph{};
0097 struct GraphAsymmErrors{};
0098 struct Profile1D{};
0099 struct Profile2D{};
0100 struct Min{};
0101 struct Max{};
0102 struct Sum{};
0103 struct Mean{};
0104 struct Fill{};
0105 struct StdDev{};
0106 struct Display{};
0107 struct Snapshot{};
0108 struct Book{};
0109 }
0110 // clang-format on
0111 
0112 template <typename T, bool ISV6HISTO = std::is_base_of<TH1, std::decay_t<T>>::value>
0113 struct HistoUtils {
0114    static bool HasAxisLimits(T &h)
0115    {
0116       auto xaxis = h.GetXaxis();
0117       return !(xaxis->GetXmin() == 0. && xaxis->GetXmax() == 0.);
0118    }
0119 };
0120 
0121 template <typename T>
0122 struct HistoUtils<T, false> {
0123    static bool HasAxisLimits(T &) { return true; }
0124 };
0125 
0126 // Generic filling (covers Histo2D, HistoND, HistoNSparseD, Profile1D and Profile2D actions, with and without weights)
0127 template <typename... ColTypes, typename ActionTag, typename ActionResultType, typename PrevNodeType>
0128 std::unique_ptr<RActionBase>
0129 BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &h, const unsigned int nSlots,
0130             std::shared_ptr<PrevNodeType> prevNode, ActionTag, const RColumnRegister &colRegister)
0131 {
0132    using Helper_t = FillHelper<ActionResultType>;
0133    using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
0134    return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister);
0135 }
0136 
0137 // Histo1D filling (must handle the special case of distinguishing FillHelper and BufferedFillHelper
0138 template <typename... ColTypes, typename PrevNodeType>
0139 std::unique_ptr<RActionBase>
0140 BuildAction(const ColumnNames_t &bl, const std::shared_ptr<::TH1D> &h, const unsigned int nSlots,
0141             std::shared_ptr<PrevNodeType> prevNode, ActionTags::Histo1D, const RColumnRegister &colRegister)
0142 {
0143    auto hasAxisLimits = HistoUtils<::TH1D>::HasAxisLimits(*h);
0144 
0145    if (hasAxisLimits || !IsImplicitMTEnabled()) {
0146       using Helper_t = FillHelper<::TH1D>;
0147       using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
0148       return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister);
0149    } else {
0150       using Helper_t = BufferedFillHelper;
0151       using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
0152       return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister);
0153    }
0154 }
0155 
0156 // Action for Histo3D, where thread safe filling might be supported to save memory
0157 template <typename... ColTypes, typename ActionResultType, typename PrevNodeType>
0158 std::unique_ptr<RActionBase>
0159 BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &h, const unsigned int nSlots,
0160             std::shared_ptr<PrevNodeType> prevNode, ActionTags::Histo3D, const RColumnRegister &colRegister)
0161 {
0162    if (RDFInternal::NThreadPerTH3() <= 1 || nSlots == 1) {
0163       using Helper_t = FillHelper<ActionResultType>;
0164       using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
0165       return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister);
0166    } else {
0167       using Helper_t = ThreadSafeFillHelper<ActionResultType>;
0168       using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
0169       if constexpr (sizeof...(ColTypes) > 3) {
0170          h->Sumw2();
0171       }
0172       const auto histoSlots = std::max(nSlots / RDFInternal::NThreadPerTH3(), 1u);
0173       return std::make_unique<Action_t>(Helper_t(h, histoSlots), bl, std::move(prevNode), colRegister);
0174    }
0175 }
0176 
0177 #ifdef R__HAS_ROOT7
0178 // Action for RHist using RHistConcurrentFiller without weights
0179 template <typename... ColTypes, typename BinContentType, typename PrevNodeType>
0180 std::unique_ptr<RActionBase>
0181 BuildAction(const ColumnNames_t &columnList, const std::shared_ptr<ROOT::Experimental::RHist<BinContentType>> &h,
0182             const unsigned int nSlots, std::shared_ptr<PrevNodeType> prevNode, ActionTags::Hist,
0183             const RColumnRegister &colRegister)
0184 {
0185    using Helper_t = RHistFillHelper<BinContentType>;
0186    using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
0187    return std::make_unique<Action_t>(Helper_t(h, nSlots), columnList, std::move(prevNode), colRegister);
0188 }
0189 
0190 // Action for RHist using RHistConcurrentFiller with weights
0191 template <typename... ColTypes, typename BinContentType, typename PrevNodeType>
0192 std::unique_ptr<RActionBase>
0193 BuildAction(const ColumnNames_t &columnList, const std::shared_ptr<ROOT::Experimental::RHist<BinContentType>> &h,
0194             const unsigned int nSlots, std::shared_ptr<PrevNodeType> prevNode, ActionTags::HistWithWeight,
0195             const RColumnRegister &colRegister)
0196 {
0197    using Helper_t = RHistFillHelper<BinContentType, true>;
0198    using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
0199    return std::make_unique<Action_t>(Helper_t(h, nSlots), columnList, std::move(prevNode), colRegister);
0200 }
0201 
0202 // Action for RHistEngine using FillAtomic without weights
0203 template <typename... ColTypes, typename BinContentType, typename PrevNodeType>
0204 std::unique_ptr<RActionBase>
0205 BuildAction(const ColumnNames_t &columnList, const std::shared_ptr<ROOT::Experimental::RHistEngine<BinContentType>> &h,
0206             const unsigned int, std::shared_ptr<PrevNodeType> prevNode, ActionTags::Hist,
0207             const RColumnRegister &colRegister)
0208 {
0209    using Helper_t = RHistEngineFillHelper<BinContentType>;
0210    using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
0211    return std::make_unique<Action_t>(Helper_t(h), columnList, std::move(prevNode), colRegister);
0212 }
0213 
0214 // Action for RHistEngine using FillAtomic with weights
0215 template <typename... ColTypes, typename BinContentType, typename PrevNodeType>
0216 std::unique_ptr<RActionBase>
0217 BuildAction(const ColumnNames_t &columnList, const std::shared_ptr<ROOT::Experimental::RHistEngine<BinContentType>> &h,
0218             const unsigned int, std::shared_ptr<PrevNodeType> prevNode, ActionTags::HistWithWeight,
0219             const RColumnRegister &colRegister)
0220 {
0221    using Helper_t = RHistEngineFillHelper<BinContentType, true>;
0222    using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
0223    return std::make_unique<Action_t>(Helper_t(h), columnList, std::move(prevNode), colRegister);
0224 }
0225 #endif
0226 
0227 template <typename... ColTypes, typename PrevNodeType>
0228 std::unique_ptr<RActionBase>
0229 BuildAction(const ColumnNames_t &bl, const std::shared_ptr<TGraph> &g, const unsigned int nSlots,
0230             std::shared_ptr<PrevNodeType> prevNode, ActionTags::Graph, const RColumnRegister &colRegister)
0231 {
0232    using Helper_t = FillTGraphHelper;
0233    using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
0234    return std::make_unique<Action_t>(Helper_t(g, nSlots), bl, std::move(prevNode), colRegister);
0235 }
0236 
0237 template <typename... ColTypes, typename PrevNodeType>
0238 std::unique_ptr<RActionBase>
0239 BuildAction(const ColumnNames_t &bl, const std::shared_ptr<TGraphAsymmErrors> &g, const unsigned int nSlots,
0240             std::shared_ptr<PrevNodeType> prevNode, ActionTags::GraphAsymmErrors, const RColumnRegister &colRegister)
0241 {
0242    using Helper_t = FillTGraphAsymmErrorsHelper;
0243    using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
0244    return std::make_unique<Action_t>(Helper_t(g, nSlots), bl, std::move(prevNode), colRegister);
0245 }
0246 
0247 // Min action
0248 template <typename ColType, typename PrevNodeType, typename ActionResultType>
0249 std::unique_ptr<RActionBase>
0250 BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &minV, const unsigned int nSlots,
0251             std::shared_ptr<PrevNodeType> prevNode, ActionTags::Min, const RColumnRegister &colRegister)
0252 {
0253    using Helper_t = MinHelper<ActionResultType>;
0254    using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColType>>;
0255    return std::make_unique<Action_t>(Helper_t(minV, nSlots), bl, std::move(prevNode), colRegister);
0256 }
0257 
0258 // Max action
0259 template <typename ColType, typename PrevNodeType, typename ActionResultType>
0260 std::unique_ptr<RActionBase>
0261 BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &maxV, const unsigned int nSlots,
0262             std::shared_ptr<PrevNodeType> prevNode, ActionTags::Max, const RColumnRegister &colRegister)
0263 {
0264    using Helper_t = MaxHelper<ActionResultType>;
0265    using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColType>>;
0266    return std::make_unique<Action_t>(Helper_t(maxV, nSlots), bl, std::move(prevNode), colRegister);
0267 }
0268 
0269 // Sum action
0270 template <typename ColType, typename PrevNodeType, typename ActionResultType>
0271 std::unique_ptr<RActionBase>
0272 BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &sumV, const unsigned int nSlots,
0273             std::shared_ptr<PrevNodeType> prevNode, ActionTags::Sum, const RColumnRegister &colRegister)
0274 {
0275    using Helper_t = SumHelper<ActionResultType>;
0276    using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColType>>;
0277    return std::make_unique<Action_t>(Helper_t(sumV, nSlots), bl, std::move(prevNode), colRegister);
0278 }
0279 
0280 // Mean action
0281 template <typename ColType, typename PrevNodeType>
0282 std::unique_ptr<RActionBase>
0283 BuildAction(const ColumnNames_t &bl, const std::shared_ptr<double> &meanV, const unsigned int nSlots,
0284             std::shared_ptr<PrevNodeType> prevNode, ActionTags::Mean, const RColumnRegister &colRegister)
0285 {
0286    using Helper_t = MeanHelper;
0287    using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColType>>;
0288    return std::make_unique<Action_t>(Helper_t(meanV, nSlots), bl, std::move(prevNode), colRegister);
0289 }
0290 
0291 // Standard Deviation action
0292 template <typename ColType, typename PrevNodeType>
0293 std::unique_ptr<RActionBase>
0294 BuildAction(const ColumnNames_t &bl, const std::shared_ptr<double> &stdDeviationV, const unsigned int nSlots,
0295             std::shared_ptr<PrevNodeType> prevNode, ActionTags::StdDev, const RColumnRegister &colRegister)
0296 {
0297    using Helper_t = StdDevHelper;
0298    using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColType>>;
0299    return std::make_unique<Action_t>(Helper_t(stdDeviationV, nSlots), bl, prevNode, colRegister);
0300 }
0301 
0302 using displayHelperArgs_t = std::pair<size_t, std::shared_ptr<ROOT::RDF::RDisplay>>;
0303 
0304 // Display action
0305 template <typename... ColTypes, typename PrevNodeType>
0306 std::unique_ptr<RActionBase>
0307 BuildAction(const ColumnNames_t &bl, const std::shared_ptr<displayHelperArgs_t> &helperArgs, const unsigned int,
0308             std::shared_ptr<PrevNodeType> prevNode, ActionTags::Display, const RColumnRegister &colRegister)
0309 {
0310    using Helper_t = DisplayHelper<PrevNodeType>;
0311    using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
0312    return std::make_unique<Action_t>(Helper_t(helperArgs->first, helperArgs->second, prevNode), bl, prevNode,
0313                                      colRegister);
0314 }
0315 
0316 struct SnapshotHelperArgs {
0317    std::string fFileName;
0318    std::string fDirName;
0319    std::string fTreeName;
0320    std::vector<std::string> fOutputColNames;
0321    ROOT::RDF::RSnapshotOptions fOptions;
0322    ROOT::Detail::RDF::RLoopManager *fOutputLoopManager;
0323    ROOT::Detail::RDF::RLoopManager *fInputLoopManager;
0324    bool fToNTuple;
0325    bool fIncludeVariations;
0326 };
0327 
0328 template <typename PrevNodeType>
0329 std::unique_ptr<RActionBase>
0330 BuildAction(const ColumnNames_t &colNames, const std::shared_ptr<SnapshotHelperArgs> &snapHelperArgs,
0331             const unsigned int nSlots, std::shared_ptr<PrevNodeType> prevNode, const RColumnRegister &colRegister,
0332             const std::vector<const std::type_info *> &colTypeIDs)
0333 {
0334    const auto &filename = snapHelperArgs->fFileName;
0335    const auto &dirname = snapHelperArgs->fDirName;
0336    const auto &treename = snapHelperArgs->fTreeName;
0337    const auto &outputColNames = snapHelperArgs->fOutputColNames;
0338    const auto &options = snapHelperArgs->fOptions;
0339    const auto &outputLM = snapHelperArgs->fOutputLoopManager;
0340    const auto &inputLM = snapHelperArgs->fInputLoopManager;
0341 
0342    auto sz = colNames.size();
0343    std::vector<bool> isDefine(sz);
0344    for (auto i = 0u; i < sz; ++i)
0345       isDefine[i] = colRegister.IsDefineOrAlias(colNames[i]);
0346 
0347    std::unique_ptr<RActionBase> actionPtr;
0348    if (snapHelperArgs->fToNTuple) {
0349       // We use the same helper for single- and multi-thread snapshot.
0350       using Helper_t = UntypedSnapshotRNTupleHelper;
0351       using Action_t = RActionSnapshot<Helper_t, PrevNodeType>;
0352 
0353       actionPtr.reset(new Action_t(Helper_t(nSlots, filename, dirname, treename, colNames, outputColNames, options,
0354                                             inputLM, outputLM, colTypeIDs),
0355                                    colNames, colTypeIDs, prevNode, colRegister));
0356    } else {
0357       if (!ROOT::IsImplicitMTEnabled()) {
0358          // single-thread snapshot
0359          if (snapHelperArgs->fIncludeVariations) {
0360             using Helper_t = SnapshotHelperWithVariations;
0361             using Action_t = RActionSnapshot<Helper_t, PrevNodeType>;
0362             actionPtr.reset(new Action_t(Helper_t(filename, dirname, treename, colNames, outputColNames, options,
0363                                                   std::move(isDefine), outputLM, inputLM, colTypeIDs),
0364                                          colNames, colTypeIDs, prevNode, colRegister));
0365          } else {
0366             using Helper_t = UntypedSnapshotTTreeHelper;
0367             using Action_t = RActionSnapshot<Helper_t, PrevNodeType>;
0368             actionPtr.reset(new Action_t(Helper_t(filename, dirname, treename, colNames, outputColNames, options,
0369                                                   std::move(isDefine), outputLM, inputLM, colTypeIDs),
0370                                          colNames, colTypeIDs, prevNode, colRegister));
0371          }
0372       } else {
0373          if (snapHelperArgs->fIncludeVariations) {
0374             throw std::invalid_argument("Multi-threaded snapshot with variations is not supported yet.");
0375          }
0376          // multi-thread snapshot
0377          using Helper_t = UntypedSnapshotTTreeHelperMT;
0378          using Action_t = RActionSnapshot<Helper_t, PrevNodeType>;
0379          actionPtr.reset(new Action_t(Helper_t(nSlots, filename, dirname, treename, colNames, outputColNames, options,
0380                                                std::move(isDefine), outputLM, inputLM, colTypeIDs),
0381                                       colNames, colTypeIDs, prevNode, colRegister));
0382       }
0383    }
0384 
0385    return actionPtr;
0386 }
0387 
0388 // Book with custom helper type
0389 template <typename... ColTypes, typename PrevNodeType, typename Helper_t>
0390 std::unique_ptr<RActionBase>
0391 BuildAction(const ColumnNames_t &bl, const std::shared_ptr<Helper_t> &h, const unsigned int /*nSlots*/,
0392             std::shared_ptr<PrevNodeType> prevNode, ActionTags::Book, const RColumnRegister &colRegister)
0393 {
0394    using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
0395    return std::make_unique<Action_t>(Helper_t(std::move(*h)), bl, std::move(prevNode), colRegister);
0396 }
0397 
0398 /****** end BuildAndBook ******/
0399 
0400 template <typename Filter>
0401 void CheckFilter(Filter &)
0402 {
0403    using FilterRet_t = typename RDF::CallableTraits<Filter>::ret_type;
0404    static_assert(std::is_convertible<FilterRet_t, bool>::value,
0405                  "filter expression returns a type that is not convertible to bool");
0406 }
0407 
0408 ColumnNames_t FilterArraySizeColNames(const ColumnNames_t &columnNames, const std::string &action);
0409 
0410 void CheckValidCppVarName(std::string_view var, const std::string &where);
0411 
0412 void CheckForRedefinition(const std::string &where, std::string_view definedCol, const RColumnRegister &colRegister,
0413                           const ColumnNames_t &dataSourceColumns);
0414 
0415 void CheckForDefinition(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister,
0416                         const ColumnNames_t &dataSourceColumns);
0417 
0418 void CheckForNoVariations(const std::string &where, std::string_view definedColView,
0419                           const RColumnRegister &colRegister);
0420 
0421 std::string PrettyPrintAddr(const void *const addr);
0422 
0423 std::shared_ptr<RJittedFilter> BookFilterJit(std::shared_ptr<RNodeBase> prevNode, std::string_view name,
0424                                              std::string_view expression, const RColumnRegister &colRegister,
0425                                              TTree *tree, RDataSource *ds);
0426 
0427 std::shared_ptr<RJittedDefine> BookDefineJit(std::string_view name, std::string_view expression, RLoopManager &lm,
0428                                              RDataSource *ds, const RColumnRegister &colRegister);
0429 
0430 std::shared_ptr<RJittedDefine> BookDefinePerSampleJit(std::string_view name, std::string_view expression,
0431                                                       RLoopManager &lm, const RColumnRegister &colRegister);
0432 
0433 std::shared_ptr<RJittedVariation>
0434 BookVariationJit(const std::vector<std::string> &colNames, std::string_view variationName,
0435                  const std::vector<std::string> &variationTags, std::string_view expression, RLoopManager &lm,
0436                  RDataSource *ds, const RColumnRegister &colRegister, bool isSingleColumn,
0437                  const std::string &varyColType);
0438 
0439 std::string JitBuildAction(const ColumnNames_t &bl, const std::type_info &art, const std::type_info &at, TTree *tree,
0440                            const unsigned int nSlots, const RColumnRegister &colRegister, RDataSource *ds,
0441                            const bool vector2RVec = true);
0442 
0443 bool AtLeastOneEmptyString(const std::vector<std::string_view> strings);
0444 
0445 /// Take a shared_ptr<AnyNodeType> and return a shared_ptr<RNodeBase>.
0446 /// This works for RLoopManager nodes as well as filters and ranges.
0447 std::shared_ptr<RNodeBase> UpcastNode(std::shared_ptr<RNodeBase> ptr);
0448 
0449 ColumnNames_t GetValidatedColumnNames(RLoopManager &lm, const unsigned int nColumns, const ColumnNames_t &columns,
0450                                       const RColumnRegister &validDefines, RDataSource *ds);
0451 
0452 std::vector<std::string> GetValidatedArgTypes(const ColumnNames_t &colNames, const RColumnRegister &colRegister,
0453                                               TTree *tree, RDataSource *ds, const std::string &context,
0454                                               bool vector2RVec);
0455 
0456 template <typename T>
0457 void AddDSColumnsHelper(const std::string &colName, RLoopManager &lm, RDataSource &ds, RColumnRegister &colRegister)
0458 {
0459 
0460    if (colRegister.IsDefineOrAlias(colName))
0461       return;
0462 
0463    if (lm.HasDataSourceColumnReaders(colName, typeid(T)))
0464       return;
0465 
0466    if (!ds.HasColumn(colName) &&
0467        lm.GetSuppressErrorsForMissingBranches().find(colName) == lm.GetSuppressErrorsForMissingBranches().end())
0468       return;
0469 
0470    const auto nSlots = lm.GetNSlots();
0471    std::vector<std::unique_ptr<RColumnReaderBase>> colReaders;
0472    colReaders.reserve(nSlots);
0473 
0474    const auto valuePtrs = ds.GetColumnReaders<T>(colName);
0475    if (!valuePtrs.empty()) { // we are using the old GetColumnReaders mechanism in this RDataSource
0476       for (auto *ptr : valuePtrs)
0477          colReaders.emplace_back(new RDSColumnReader<T>(ptr));
0478 
0479    } else { // using the new GetColumnReaders mechanism
0480       // TODO consider changing the interface so we return all of these for all slots in one go
0481       for (auto slot = 0u; slot < lm.GetNSlots(); ++slot)
0482          colReaders.emplace_back(
0483             ROOT::Internal::RDF::CreateColumnReader(ds, slot, colName, typeid(T), /*treeReader*/ nullptr));
0484    }
0485 
0486    lm.AddDataSourceColumnReaders(colName, std::move(colReaders), typeid(T));
0487 }
0488 
0489 /// Take list of column names that must be defined, current map of custom columns, current list of defined column names,
0490 /// and return a new map of custom columns (with the new datasource columns added to it)
0491 template <typename... ColumnTypes>
0492 void AddDSColumns(const std::vector<std::string> &requiredCols, RLoopManager &lm, RDataSource &ds,
0493                   TTraits::TypeList<ColumnTypes...>, RColumnRegister &colRegister)
0494 {
0495    // hack to expand a template parameter pack without c++17 fold expressions.
0496    using expander = int[];
0497    int i = 0;
0498    (void)expander{(AddDSColumnsHelper<ColumnTypes>(requiredCols[i], lm, ds, colRegister), ++i)..., 0};
0499 }
0500 
0501 void AddDSColumns(const std::vector<std::string> &requiredCols, ROOT::Detail::RDF::RLoopManager &lm,
0502                   ROOT::RDF::RDataSource &ds, const std::vector<const std::type_info *> &colTypeIDs,
0503                   ROOT::Internal::RDF::RColumnRegister &colRegister);
0504 
0505 // this function is meant to be called by the jitted code generated by BookFilterJit
0506 template <typename F>
0507 void JitFilterHelper(F &&f, const ColumnNames_t &cols, RColumnRegister &colRegister,
0508                      ROOT::Detail::RDF::RLoopManager &lm, ROOT::Detail::RDF::RJittedFilter *jittedFilter) noexcept
0509 {
0510    if (!jittedFilter) {
0511       // The branch of the computation graph that needed this jitted code went out of scope between the type
0512       // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
0513       return;
0514    }
0515 
0516    // mock Filter logic -- validity checks and Define-ition of RDataSource columns
0517    using Callable_t = std::decay_t<F>;
0518    auto prevNode = jittedFilter->MoveOutPrevNode();
0519    using PrevNode_t = typename decltype(prevNode)::element_type;
0520    using F_t = RFilter<Callable_t, PrevNode_t>;
0521    using ColTypes_t = typename TTraits::CallableTraits<Callable_t>::arg_types;
0522    constexpr auto nColumns = ColTypes_t::list_size;
0523    CheckFilter(f);
0524 
0525    auto ds = lm.GetDataSource();
0526 
0527    if (ds != nullptr && !cols.empty())
0528       AddDSColumns(cols, lm, *ds, ColTypes_t(), colRegister);
0529 
0530    jittedFilter->SetFilter(
0531       std::unique_ptr<RFilterBase>(new F_t(std::forward<F>(f), cols, prevNode, colRegister, jittedFilter->GetName())));
0532 }
0533 
0534 namespace DefineTypes {
0535 struct RDefineTag {};
0536 struct RDefinePerSampleTag {};
0537 }
0538 
0539 template <typename F>
0540 auto MakeDefineNode(DefineTypes::RDefineTag, std::string_view name, std::string_view dummyType, F &&f,
0541                     const ColumnNames_t &cols, RColumnRegister &colRegister, RLoopManager &lm)
0542 {
0543    return std::unique_ptr<RDefineBase>(new RDefine<std::decay_t<F>, ExtraArgsForDefine::None>(
0544       name, dummyType, std::forward<F>(f), cols, colRegister, lm));
0545 }
0546 
0547 template <typename F>
0548 auto MakeDefineNode(DefineTypes::RDefinePerSampleTag, std::string_view name, std::string_view dummyType, F &&f,
0549                     const ColumnNames_t &, RColumnRegister &, RLoopManager &lm)
0550 {
0551    return std::unique_ptr<RDefineBase>(
0552       new RDefinePerSample<std::decay_t<F>>(name, dummyType, std::forward<F>(f), lm));
0553 }
0554 
0555 // Build a RDefine or a RDefinePerSample object and attach it to an existing RJittedDefine
0556 // This function is meant to be called by jitted code right before starting the event loop.
0557 // If colsPtr is null, build a RDefinePerSample (it has no input columns), otherwise a RDefine.
0558 template <typename RDefineTypeTag, typename F>
0559 void JitDefineHelper(F &&f, const ColumnNames_t &cols, RColumnRegister &colRegister,
0560                      ROOT::Detail::RDF::RLoopManager &lm, ROOT::Detail::RDF::RJittedDefine *jittedDefine) noexcept
0561 {
0562 
0563    if (!jittedDefine) {
0564       // The branch of the computation graph that needed this jitted code went out of scope between the type
0565       // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
0566       return;
0567    }
0568 
0569    using Callable_t = std::decay_t<F>;
0570    using ColTypes_t = typename TTraits::CallableTraits<Callable_t>::arg_types;
0571 
0572    auto ds = lm.GetDataSource();
0573    if (ds != nullptr && !cols.empty())
0574       AddDSColumns(cols, lm, *ds, ColTypes_t(), colRegister);
0575 
0576    // will never actually be used (trumped by jittedDefine->GetTypeName()), but we set it to something meaningful
0577    // to help devs debugging
0578    const auto dummyType = "jittedCol_t";
0579    // use unique_ptr<RDefineBase> instead of make_unique<NewCol_t> to reduce jit/compile-times
0580    std::unique_ptr<RDefineBase> newCol{
0581       MakeDefineNode(RDefineTypeTag{}, jittedDefine->GetName(), dummyType, std::forward<F>(f), cols, colRegister, lm)};
0582    jittedDefine->SetDefine(std::move(newCol));
0583 }
0584 
0585 template <bool IsSingleColumn, typename F>
0586 void JitVariationHelper(F &&f, const ColumnNames_t &inputColNames, RColumnRegister &colRegister,
0587                         ROOT::Detail::RDF::RLoopManager &lm, RJittedVariation *jittedVariation,
0588                         const ColumnNames_t &variedColNames, const ColumnNames_t &variationTags) noexcept
0589 {
0590 
0591    if (!jittedVariation) {
0592       // The branch of the computation graph that needed this jitted variation went out of scope between the type
0593       // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
0594       return;
0595    }
0596 
0597    using Callable_t = std::decay_t<F>;
0598    using ColTypes_t = typename TTraits::CallableTraits<Callable_t>::arg_types;
0599 
0600    auto ds = lm.GetDataSource();
0601    if (ds != nullptr && !inputColNames.empty())
0602       AddDSColumns(inputColNames, lm, *ds, ColTypes_t(), colRegister);
0603 
0604    // use unique_ptr<RDefineBase> instead of make_unique<NewCol_t> to reduce jit/compile-times
0605    std::unique_ptr<RVariationBase> newVariation{new RVariation<std::decay_t<F>, IsSingleColumn>(
0606       variedColNames, jittedVariation->GetVariationName(), std::forward<F>(f), variationTags,
0607       jittedVariation->GetTypeName(), colRegister, lm, inputColNames)};
0608    jittedVariation->SetVariation(std::move(newVariation));
0609 }
0610 
0611 /// Convenience function invoked by jitted code to build action nodes at runtime
0612 template <typename ActionTag, typename... ColTypes, typename HelperArgType>
0613 void CallBuildAction(const ColumnNames_t &cols, RColumnRegister &colRegister, ROOT::Detail::RDF::RLoopManager &lm,
0614                      RJittedAction *jittedAction, unsigned int nSlots,
0615                      std::shared_ptr<HelperArgType> *helperArg) noexcept
0616 {
0617    if (!jittedAction) {
0618       // The branch of the computation graph that needed this jitted variation went out of scope between the type
0619       // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
0620       return;
0621    }
0622 
0623    using ColTypes_t = TypeList<ColTypes...>;
0624    constexpr auto nColumns = ColTypes_t::list_size;
0625    auto ds = lm.GetDataSource();
0626    if (ds != nullptr && !cols.empty())
0627       AddDSColumns(cols, lm, *ds, ColTypes_t(), colRegister);
0628 
0629    auto actionPtr =
0630       BuildAction<ColTypes...>(cols, *helperArg, nSlots, jittedAction->MoveOutPrevNode(), ActionTag{}, colRegister);
0631    jittedAction->SetAction(std::move(actionPtr));
0632 }
0633 
0634 /// The contained `type` alias is `double` if `T == RInferredType`, `U` if `T == std::container<U>`, `T` otherwise.
0635 template <typename T, bool Container = IsDataContainer<T>::value && !std::is_same<T, std::string>::value>
0636 struct RMinReturnType {
0637    using type = T;
0638 };
0639 
0640 template <>
0641 struct RMinReturnType<RInferredType, false> {
0642    using type = double;
0643 };
0644 
0645 template <typename T>
0646 struct RMinReturnType<T, true> {
0647    using type = TTraits::TakeFirstParameter_t<T>;
0648 };
0649 
0650 // return wrapper around f that prepends an `unsigned int slot` parameter
0651 template <typename R, typename F, typename... Args>
0652 std::function<R(unsigned int, Args...)> AddSlotParameter(F &f, TypeList<Args...>)
0653 {
0654    return [f](unsigned int, Args... a) mutable -> R { return f(a...); };
0655 }
0656 
0657 template <typename ColType, typename... Rest>
0658 struct RNeedJittingHelper {
0659    static constexpr bool value = RNeedJittingHelper<Rest...>::value;
0660 };
0661 
0662 template <typename... Rest>
0663 struct RNeedJittingHelper<RInferredType, Rest...> {
0664    static constexpr bool value = true;
0665 };
0666 
0667 template <typename T>
0668 struct RNeedJittingHelper<T> {
0669    static constexpr bool value = false;
0670 };
0671 
0672 template <>
0673 struct RNeedJittingHelper<RInferredType> {
0674    static constexpr bool value = true;
0675 };
0676 
0677 template <typename ...ColTypes>
0678 struct RNeedJitting {
0679    static constexpr bool value = RNeedJittingHelper<ColTypes...>::value;
0680 };
0681 
0682 template <>
0683 struct RNeedJitting<> {
0684    static constexpr bool value = false;
0685 };
0686 
0687 ///////////////////////////////////////////////////////////////////////////////
0688 /// Check preconditions for RInterface::Aggregate:
0689 /// - the aggregator callable must have signature `U(U,T)` or `void(U&,T)`.
0690 /// - the merge callable must have signature `U(U,U)` or `void(std::vector<U>&)`
0691 template <typename R, typename Merge, typename U, typename T, typename decayedU = std::decay_t<U>,
0692           typename mergeArgsNoDecay_t = typename CallableTraits<Merge>::arg_types_nodecay,
0693           typename mergeArgs_t = typename CallableTraits<Merge>::arg_types,
0694           typename mergeRet_t = typename CallableTraits<Merge>::ret_type>
0695 void CheckAggregate(TypeList<U, T>)
0696 {
0697    constexpr bool isAggregatorOk =
0698       (std::is_same<R, decayedU>::value) || (std::is_same<R, void>::value && std::is_lvalue_reference<U>::value);
0699    static_assert(isAggregatorOk, "aggregator function must have signature `U(U,T)` or `void(U&,T)`");
0700    constexpr bool isMergeOk =
0701       (std::is_same<TypeList<decayedU, decayedU>, mergeArgs_t>::value && std::is_same<decayedU, mergeRet_t>::value) ||
0702       (std::is_same<TypeList<std::vector<decayedU> &>, mergeArgsNoDecay_t>::value &&
0703        std::is_same<void, mergeRet_t>::value);
0704    static_assert(isMergeOk, "merge function must have signature `U(U,U)` or `void(std::vector<U>&)`");
0705 }
0706 
0707 ///////////////////////////////////////////////////////////////////////////////
0708 /// This overload of CheckAggregate is called when the aggregator takes more than two arguments
0709 template <typename R, typename T>
0710 void CheckAggregate(T)
0711 {
0712    static_assert(sizeof(T) == 0, "aggregator function must take exactly two arguments");
0713 }
0714 
0715 ///////////////////////////////////////////////////////////////////////////////
0716 /// Check as many template parameters were passed as the number of column names, throw if this is not the case.
0717 void CheckTypesAndPars(unsigned int nTemplateParams, unsigned int nColumnNames);
0718 
0719 /// Return local BranchNames or default BranchNames according to which one should be used
0720 const ColumnNames_t SelectColumns(unsigned int nArgs, const ColumnNames_t &bl, const ColumnNames_t &defBl);
0721 
0722 /// Check whether column names refer to a valid branch of a TTree or have been `Define`d. Return invalid column names.
0723 ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, const RColumnRegister &definedCols,
0724                                  const ColumnNames_t &dataSourceColumns);
0725 
0726 /// Returns the list of Filters defined in the whole graph
0727 std::vector<std::string> GetFilterNames(const std::shared_ptr<RLoopManager> &loopManager);
0728 
0729 /// Returns the list of Filters defined in the branch
0730 template <typename NodeType>
0731 std::vector<std::string> GetFilterNames(const std::shared_ptr<NodeType> &node)
0732 {
0733    std::vector<std::string> filterNames;
0734    node->AddFilterName(filterNames);
0735    return filterNames;
0736 }
0737 
0738 struct ParsedTreePath {
0739    std::string fTreeName;
0740    std::string fDirName;
0741 };
0742 
0743 ParsedTreePath ParseTreePath(std::string_view fullTreeName);
0744 
0745 // Check if a condition is true for all types
0746 template <bool...>
0747 struct TBoolPack;
0748 
0749 template <bool... bs>
0750 using IsTrueForAllImpl_t = typename std::is_same<TBoolPack<bs..., true>, TBoolPack<true, bs...>>;
0751 
0752 template <bool... Conditions>
0753 struct TEvalAnd {
0754    static constexpr bool value = IsTrueForAllImpl_t<Conditions...>::value;
0755 };
0756 
0757 // Check if a class is a specialisation of stl containers templates
0758 // clang-format off
0759 
0760 template <typename>
0761 struct IsList_t : std::false_type {};
0762 
0763 template <typename T>
0764 struct IsList_t<std::list<T>> : std::true_type {};
0765 
0766 template <typename>
0767 struct IsDeque_t : std::false_type {};
0768 
0769 template <typename T>
0770 struct IsDeque_t<std::deque<T>> : std::true_type {};
0771 // clang-format on
0772 
0773 void CheckForDuplicateSnapshotColumns(const ColumnNames_t &cols);
0774 
0775 void CheckSnapshotOptionsFormatCompatibility(const ROOT::RDF::RSnapshotOptions &opts);
0776 
0777 template <typename T>
0778 struct InnerValueType {
0779    using type = T; // fallback for when T is not a nested RVec
0780 };
0781 
0782 template <typename Elem>
0783 struct InnerValueType<ROOT::VecOps::RVec<ROOT::VecOps::RVec<Elem>>> {
0784    using type = Elem;
0785 };
0786 
0787 template <typename T>
0788 using InnerValueType_t = typename InnerValueType<T>::type;
0789 
0790 std::pair<std::vector<std::string>, std::vector<std::string>>
0791 AddSizeBranches(ROOT::RDF::RDataSource *ds, std::vector<std::string> &&colsWithoutAliases,
0792                 std::vector<std::string> &&colsWithAliases);
0793 
0794 void RemoveDuplicates(ColumnNames_t &columnNames);
0795 void RemoveRNTupleSubfields(ColumnNames_t &columnNames);
0796 
0797 } // namespace RDF
0798 } // namespace Internal
0799 
0800 namespace Detail {
0801 namespace RDF {
0802 
0803 /// The aliased type is `double` if `T == RInferredType`, `U` if `T == container<U>`, `T` otherwise.
0804 template <typename T>
0805 using MinReturnType_t = typename RDFInternal::RMinReturnType<T>::type;
0806 
0807 template <typename T>
0808 using MaxReturnType_t = MinReturnType_t<T>;
0809 
0810 template <typename T>
0811 using SumReturnType_t = MinReturnType_t<T>;
0812 
0813 } // namespace RDF
0814 } // namespace Detail
0815 } // namespace ROOT
0816 
0817 /// \endcond
0818 
0819 #endif