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