Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
InterfaceUtils.hxx
Go to the documentation of this file.
1// Author: Enrico Guiraud, Danilo Piparo CERN 02/2018
2
3/*************************************************************************
4 * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
11#ifndef ROOT_RDF_TINTERFACE_UTILS
12#define ROOT_RDF_TINTERFACE_UTILS
13
14#include <ROOT/RDF/RAction.hxx>
16#include <ROOT/RDF/ActionHelpers.hxx> // for BuildAction
19#include <ROOT/RDF/RDefine.hxx>
21#include <ROOT/RDF/RFilter.hxx>
22#include <ROOT/RDF/Utils.hxx>
28#include <string_view>
30#include <ROOT/TypeTraits.hxx>
31#include <RConfigure.h> // for R__HAS_ROOT7
32#include <TError.h> // gErrorIgnoreLevel
33#include <TH1.h>
34#include <TROOT.h> // IsImplicitMTEnabled
35
36#include <deque>
37#include <functional>
38#include <list>
39#include <memory>
40#include <string>
41#include <type_traits>
42#include <typeinfo>
43#include <vector>
44
45class TTree;
46namespace ROOT {
47namespace Detail {
48namespace RDF {
49class RNodeBase;
50}
51}
52namespace RDF {
53template <typename Proxied>
54class RInterface;
56} // namespace RDF
57
58} // namespace ROOT
59
60/// \cond HIDDEN_SYMBOLS
61
62namespace ROOT {
63namespace Internal {
64namespace RDF {
65using namespace ROOT::Detail::RDF;
66using namespace ROOT::RDF;
67namespace TTraits = ROOT::TypeTraits;
68
69std::string DemangleTypeIdName(const std::type_info &typeInfo);
70
71ColumnNames_t
72ConvertRegexToColumns(const ColumnNames_t &colNames, std::string_view columnNameRegexp, std::string_view callerName);
73
74/// An helper object that sets and resets gErrorIgnoreLevel via RAII.
76private:
78
79public:
82};
83
84/****** BuildAction overloads *******/
85
86// clang-format off
87/// This namespace defines types to be used for tag dispatching in RInterface.
88namespace ActionTags {
89struct Histo1D{};
90struct Histo2D{};
91struct Histo3D{};
92struct HistoND{};
93struct HistoNSparseD{};
94struct Hist{};
95struct HistWithWeight{};
96struct Graph{};
97struct GraphAsymmErrors{};
98struct Profile1D{};
99struct Profile2D{};
100struct Min{};
101struct Max{};
102struct Sum{};
103struct Mean{};
104struct Fill{};
105struct StdDev{};
106struct Display{};
107struct Snapshot{};
108struct Book{};
109}
110// clang-format on
111
112template <typename T, bool ISV6HISTO = std::is_base_of<TH1, std::decay_t<T>>::value>
113struct HistoUtils {
114 static bool HasAxisLimits(T &h)
115 {
116 auto xaxis = h.GetXaxis();
117 return !(xaxis->GetXmin() == 0. && xaxis->GetXmax() == 0.);
118 }
119};
120
121template <typename T>
122struct HistoUtils<T, false> {
123 static bool HasAxisLimits(T &) { return true; }
124};
125
126// Generic filling (covers Histo2D, HistoND, HistoNSparseD, Profile1D and Profile2D actions, with and without weights)
127template <typename... ColTypes, typename ActionTag, typename ActionResultType, typename PrevNodeType>
128std::unique_ptr<RActionBase>
129BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &h, const unsigned int nSlots,
130 std::shared_ptr<PrevNodeType> prevNode, ActionTag, const RColumnRegister &colRegister)
131{
133 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
134 return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister);
135}
136
137// Histo1D filling (must handle the special case of distinguishing FillHelper and BufferedFillHelper
138template <typename... ColTypes, typename PrevNodeType>
139std::unique_ptr<RActionBase>
140BuildAction(const ColumnNames_t &bl, const std::shared_ptr<::TH1D> &h, const unsigned int nSlots,
141 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Histo1D, const RColumnRegister &colRegister)
142{
144
147 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
148 return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister);
149 } else {
151 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
152 return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister);
153 }
154}
155
156// Action for Histo3D, where thread safe filling might be supported to save memory
157template <typename... ColTypes, typename ActionResultType, typename PrevNodeType>
158std::unique_ptr<RActionBase>
159BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &h, const unsigned int nSlots,
160 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Histo3D, const RColumnRegister &colRegister)
161{
162 if (RDFInternal::NThreadPerTH3() <= 1 || nSlots == 1) {
164 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
165 return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister);
166 } else {
168 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
169 if constexpr (sizeof...(ColTypes) > 3) {
170 h->Sumw2();
171 }
172 const auto histoSlots = std::max(nSlots / RDFInternal::NThreadPerTH3(), 1u);
173 return std::make_unique<Action_t>(Helper_t(h, histoSlots), bl, std::move(prevNode), colRegister);
174 }
175}
176
177#ifdef R__HAS_ROOT7
178// Action for RHist using RHistConcurrentFiller without weights
179template <typename... ColTypes, typename BinContentType, typename PrevNodeType>
180std::unique_ptr<RActionBase>
181BuildAction(const ColumnNames_t &columnList, const std::shared_ptr<ROOT::Experimental::RHist<BinContentType>> &h,
182 const unsigned int nSlots, std::shared_ptr<PrevNodeType> prevNode, ActionTags::Hist,
183 const RColumnRegister &colRegister)
184{
186 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
187 return std::make_unique<Action_t>(Helper_t(h, nSlots), columnList, std::move(prevNode), colRegister);
188}
189
190// Action for RHist using RHistConcurrentFiller with weights
191template <typename... ColTypes, typename BinContentType, typename PrevNodeType>
192std::unique_ptr<RActionBase>
193BuildAction(const ColumnNames_t &columnList, const std::shared_ptr<ROOT::Experimental::RHist<BinContentType>> &h,
194 const unsigned int nSlots, std::shared_ptr<PrevNodeType> prevNode, ActionTags::HistWithWeight,
195 const RColumnRegister &colRegister)
196{
198 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
199 return std::make_unique<Action_t>(Helper_t(h, nSlots), columnList, std::move(prevNode), colRegister);
200}
201
202// Action for RHistEngine using FillAtomic without weights
203template <typename... ColTypes, typename BinContentType, typename PrevNodeType>
204std::unique_ptr<RActionBase>
205BuildAction(const ColumnNames_t &columnList, const std::shared_ptr<ROOT::Experimental::RHistEngine<BinContentType>> &h,
206 const unsigned int, std::shared_ptr<PrevNodeType> prevNode, ActionTags::Hist,
207 const RColumnRegister &colRegister)
208{
210 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
211 return std::make_unique<Action_t>(Helper_t(h), columnList, std::move(prevNode), colRegister);
212}
213
214// Action for RHistEngine using FillAtomic with weights
215template <typename... ColTypes, typename BinContentType, typename PrevNodeType>
216std::unique_ptr<RActionBase>
217BuildAction(const ColumnNames_t &columnList, const std::shared_ptr<ROOT::Experimental::RHistEngine<BinContentType>> &h,
218 const unsigned int, std::shared_ptr<PrevNodeType> prevNode, ActionTags::HistWithWeight,
219 const RColumnRegister &colRegister)
220{
222 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
223 return std::make_unique<Action_t>(Helper_t(h), columnList, std::move(prevNode), colRegister);
224}
225#endif
226
227template <typename... ColTypes, typename PrevNodeType>
228std::unique_ptr<RActionBase>
229BuildAction(const ColumnNames_t &bl, const std::shared_ptr<TGraph> &g, const unsigned int nSlots,
230 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Graph, const RColumnRegister &colRegister)
231{
233 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
234 return std::make_unique<Action_t>(Helper_t(g, nSlots), bl, std::move(prevNode), colRegister);
235}
236
237template <typename... ColTypes, typename PrevNodeType>
238std::unique_ptr<RActionBase>
239BuildAction(const ColumnNames_t &bl, const std::shared_ptr<TGraphAsymmErrors> &g, const unsigned int nSlots,
240 std::shared_ptr<PrevNodeType> prevNode, ActionTags::GraphAsymmErrors, const RColumnRegister &colRegister)
241{
243 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
244 return std::make_unique<Action_t>(Helper_t(g, nSlots), bl, std::move(prevNode), colRegister);
245}
246
247// Min action
248template <typename ColType, typename PrevNodeType, typename ActionResultType>
249std::unique_ptr<RActionBase>
250BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &minV, const unsigned int nSlots,
251 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Min, const RColumnRegister &colRegister)
252{
255 return std::make_unique<Action_t>(Helper_t(minV, nSlots), bl, std::move(prevNode), colRegister);
256}
257
258// Max action
259template <typename ColType, typename PrevNodeType, typename ActionResultType>
260std::unique_ptr<RActionBase>
261BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &maxV, const unsigned int nSlots,
262 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Max, const RColumnRegister &colRegister)
263{
266 return std::make_unique<Action_t>(Helper_t(maxV, nSlots), bl, std::move(prevNode), colRegister);
267}
268
269// Sum action
270template <typename ColType, typename PrevNodeType, typename ActionResultType>
271std::unique_ptr<RActionBase>
272BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &sumV, const unsigned int nSlots,
273 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Sum, const RColumnRegister &colRegister)
274{
277 return std::make_unique<Action_t>(Helper_t(sumV, nSlots), bl, std::move(prevNode), colRegister);
278}
279
280// Mean action
281template <typename ColType, typename PrevNodeType>
282std::unique_ptr<RActionBase>
283BuildAction(const ColumnNames_t &bl, const std::shared_ptr<double> &meanV, const unsigned int nSlots,
284 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Mean, const RColumnRegister &colRegister)
285{
286 using Helper_t = MeanHelper;
288 return std::make_unique<Action_t>(Helper_t(meanV, nSlots), bl, std::move(prevNode), colRegister);
289}
290
291// Standard Deviation action
292template <typename ColType, typename PrevNodeType>
293std::unique_ptr<RActionBase>
294BuildAction(const ColumnNames_t &bl, const std::shared_ptr<double> &stdDeviationV, const unsigned int nSlots,
295 std::shared_ptr<PrevNodeType> prevNode, ActionTags::StdDev, const RColumnRegister &colRegister)
296{
297 using Helper_t = StdDevHelper;
299 return std::make_unique<Action_t>(Helper_t(stdDeviationV, nSlots), bl, prevNode, colRegister);
300}
301
302using displayHelperArgs_t = std::pair<size_t, std::shared_ptr<ROOT::RDF::RDisplay>>;
303
304// Display action
305template <typename... ColTypes, typename PrevNodeType>
306std::unique_ptr<RActionBase>
307BuildAction(const ColumnNames_t &bl, const std::shared_ptr<displayHelperArgs_t> &helperArgs, const unsigned int,
308 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Display, const RColumnRegister &colRegister)
309{
311 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
312 return std::make_unique<Action_t>(Helper_t(helperArgs->first, helperArgs->second, prevNode), bl, prevNode,
314}
315
316struct SnapshotHelperArgs {
317 std::string fFileName;
318 std::string fDirName;
319 std::string fTreeName;
320 std::vector<std::string> fOutputColNames;
322 ROOT::Detail::RDF::RLoopManager *fOutputLoopManager;
323 ROOT::Detail::RDF::RLoopManager *fInputLoopManager;
324 bool fToNTuple;
325 bool fIncludeVariations;
326};
327
328template <typename PrevNodeType>
329std::unique_ptr<RActionBase>
330BuildAction(const ColumnNames_t &colNames, const std::shared_ptr<SnapshotHelperArgs> &snapHelperArgs,
331 const unsigned int nSlots, std::shared_ptr<PrevNodeType> prevNode, const RColumnRegister &colRegister,
332 const std::vector<const std::type_info *> &colTypeIDs)
333{
334 const auto &filename = snapHelperArgs->fFileName;
335 const auto &dirname = snapHelperArgs->fDirName;
336 const auto &treename = snapHelperArgs->fTreeName;
337 const auto &outputColNames = snapHelperArgs->fOutputColNames;
338 const auto &options = snapHelperArgs->fOptions;
339 const auto &outputLM = snapHelperArgs->fOutputLoopManager;
340 const auto &inputLM = snapHelperArgs->fInputLoopManager;
341
342 auto sz = colNames.size();
343 std::vector<bool> isDefine(sz);
344 for (auto i = 0u; i < sz; ++i)
345 isDefine[i] = colRegister.IsDefineOrAlias(colNames[i]);
346
347 std::unique_ptr<RActionBase> actionPtr;
348 if (snapHelperArgs->fToNTuple) {
349 // We use the same helper for single- and multi-thread snapshot.
350 using Helper_t = UntypedSnapshotRNTupleHelper;
352
355 colNames, colTypeIDs, prevNode, colRegister));
356 } else {
358 // single-thread snapshot
359 if (snapHelperArgs->fIncludeVariations) {
360 using Helper_t = SnapshotHelperWithVariations;
363 std::move(isDefine), outputLM, inputLM, colTypeIDs),
364 colNames, colTypeIDs, prevNode, colRegister));
365 } else {
366 using Helper_t = UntypedSnapshotTTreeHelper;
369 std::move(isDefine), outputLM, inputLM, colTypeIDs),
370 colNames, colTypeIDs, prevNode, colRegister));
371 }
372 } else {
373 if (snapHelperArgs->fIncludeVariations) {
374 throw std::invalid_argument("Multi-threaded snapshot with variations is not supported yet.");
375 }
376 // multi-thread snapshot
377 using Helper_t = UntypedSnapshotTTreeHelperMT;
380 std::move(isDefine), outputLM, inputLM, colTypeIDs),
381 colNames, colTypeIDs, prevNode, colRegister));
382 }
383 }
384
385 return actionPtr;
386}
387
388// Book with custom helper type
389template <typename... ColTypes, typename PrevNodeType, typename Helper_t>
390std::unique_ptr<RActionBase>
391BuildAction(const ColumnNames_t &bl, const std::shared_ptr<Helper_t> &h, const unsigned int /*nSlots*/,
392 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Book, const RColumnRegister &colRegister)
393{
394 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
395 return std::make_unique<Action_t>(Helper_t(std::move(*h)), bl, std::move(prevNode), colRegister);
396}
397
398/****** end BuildAndBook ******/
399
400template <typename Filter>
401void CheckFilter(Filter &)
402{
403 using FilterRet_t = typename RDF::CallableTraits<Filter>::ret_type;
404 static_assert(std::is_convertible<FilterRet_t, bool>::value,
405 "filter expression returns a type that is not convertible to bool");
406}
407
408ColumnNames_t FilterArraySizeColNames(const ColumnNames_t &columnNames, const std::string &action);
409
410void CheckValidCppVarName(std::string_view var, const std::string &where);
411
412void CheckForRedefinition(const std::string &where, std::string_view definedCol, const RColumnRegister &colRegister,
413 const ColumnNames_t &dataSourceColumns);
414
415void CheckForDefinition(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister,
416 const ColumnNames_t &dataSourceColumns);
417
418void CheckForNoVariations(const std::string &where, std::string_view definedColView,
419 const RColumnRegister &colRegister);
420
421std::string PrettyPrintAddr(const void *const addr);
422
423std::shared_ptr<RJittedFilter> BookFilterJit(std::shared_ptr<RNodeBase> prevNode, std::string_view name,
424 std::string_view expression, const RColumnRegister &colRegister,
425 TTree *tree, RDataSource *ds);
426
427std::shared_ptr<RJittedDefine> BookDefineJit(std::string_view name, std::string_view expression, RLoopManager &lm,
428 RDataSource *ds, const RColumnRegister &colRegister);
429
430std::shared_ptr<RJittedDefine> BookDefinePerSampleJit(std::string_view name, std::string_view expression,
431 RLoopManager &lm, const RColumnRegister &colRegister);
432
433std::shared_ptr<RJittedVariation>
434BookVariationJit(const std::vector<std::string> &colNames, std::string_view variationName,
435 const std::vector<std::string> &variationTags, std::string_view expression, RLoopManager &lm,
436 RDataSource *ds, const RColumnRegister &colRegister, bool isSingleColumn);
437
438std::string JitBuildAction(const ColumnNames_t &bl, const std::type_info &art, const std::type_info &at, TTree *tree,
439 const unsigned int nSlots, const RColumnRegister &colRegister, RDataSource *ds,
440 const bool vector2RVec = true);
441
442// Allocate a weak_ptr on the heap, return a pointer to it. The user is responsible for deleting this weak_ptr.
443// This function is meant to be used by RInterface's methods that book code for jitting.
444// The problem it solves is that we generate code to be lazily jitted with the addresses of certain objects in them,
445// and we need to check those objects are still alive when the generated code is finally jitted and executed.
446// So we pass addresses to weak_ptrs allocated on the heap to the jitted code, which is then responsible for
447// the deletion of the weak_ptr object.
448template <typename T>
449std::weak_ptr<T> *MakeWeakOnHeap(const std::shared_ptr<T> &shPtr)
450{
451 return new std::weak_ptr<T>(shPtr);
452}
453
454// Same as MakeWeakOnHeap, but create a shared_ptr that makes sure the object is definitely kept alive.
455template <typename T>
456std::shared_ptr<T> *MakeSharedOnHeap(const std::shared_ptr<T> &shPtr)
457{
458 return new std::shared_ptr<T>(shPtr);
459}
460
461bool AtLeastOneEmptyString(const std::vector<std::string_view> strings);
462
463/// Take a shared_ptr<AnyNodeType> and return a shared_ptr<RNodeBase>.
464/// This works for RLoopManager nodes as well as filters and ranges.
465std::shared_ptr<RNodeBase> UpcastNode(std::shared_ptr<RNodeBase> ptr);
466
467ColumnNames_t GetValidatedColumnNames(RLoopManager &lm, const unsigned int nColumns, const ColumnNames_t &columns,
468 const RColumnRegister &validDefines, RDataSource *ds);
469
470std::vector<std::string> GetValidatedArgTypes(const ColumnNames_t &colNames, const RColumnRegister &colRegister,
471 TTree *tree, RDataSource *ds, const std::string &context,
472 bool vector2RVec);
473
474template <typename T>
475void AddDSColumnsHelper(const std::string &colName, RLoopManager &lm, RDataSource &ds, RColumnRegister &colRegister)
476{
477
478 if (colRegister.IsDefineOrAlias(colName))
479 return;
480
481 if (lm.HasDataSourceColumnReaders(colName, typeid(T)))
482 return;
483
484 if (!ds.HasColumn(colName) &&
485 lm.GetSuppressErrorsForMissingBranches().find(colName) == lm.GetSuppressErrorsForMissingBranches().end())
486 return;
487
488 const auto nSlots = lm.GetNSlots();
489 std::vector<std::unique_ptr<RColumnReaderBase>> colReaders;
490 colReaders.reserve(nSlots);
491
492 const auto valuePtrs = ds.GetColumnReaders<T>(colName);
493 if (!valuePtrs.empty()) { // we are using the old GetColumnReaders mechanism in this RDataSource
494 for (auto *ptr : valuePtrs)
495 colReaders.emplace_back(new RDSColumnReader<T>(ptr));
496
497 } else { // using the new GetColumnReaders mechanism
498 // TODO consider changing the interface so we return all of these for all slots in one go
499 for (auto slot = 0u; slot < lm.GetNSlots(); ++slot)
500 colReaders.emplace_back(
501 ROOT::Internal::RDF::CreateColumnReader(ds, slot, colName, typeid(T), /*treeReader*/ nullptr));
502 }
503
504 lm.AddDataSourceColumnReaders(colName, std::move(colReaders), typeid(T));
505}
506
507/// Take list of column names that must be defined, current map of custom columns, current list of defined column names,
508/// and return a new map of custom columns (with the new datasource columns added to it)
509template <typename... ColumnTypes>
510void AddDSColumns(const std::vector<std::string> &requiredCols, RLoopManager &lm, RDataSource &ds,
512{
513 // hack to expand a template parameter pack without c++17 fold expressions.
514 using expander = int[];
515 int i = 0;
517}
518
519void AddDSColumns(const std::vector<std::string> &requiredCols, ROOT::Detail::RDF::RLoopManager &lm,
520 ROOT::RDF::RDataSource &ds, const std::vector<const std::type_info *> &colTypeIDs,
522
523// this function is meant to be called by the jitted code generated by BookFilterJit
524template <typename F>
525void JitFilterHelper(F &&f, const ColumnNames_t &cols, RColumnRegister &colRegister,
527{
528 if (!jittedFilter) {
529 // The branch of the computation graph that needed this jitted code went out of scope between the type
530 // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
531 return;
532 }
533
534 // mock Filter logic -- validity checks and Define-ition of RDataSource columns
535 using Callable_t = std::decay_t<F>;
536 auto prevNode = jittedFilter->MoveOutPrevNode();
537 using PrevNode_t = typename decltype(prevNode)::element_type;
539 using ColTypes_t = typename TTraits::CallableTraits<Callable_t>::arg_types;
540 constexpr auto nColumns = ColTypes_t::list_size;
541 CheckFilter(f);
542
543 auto ds = lm.GetDataSource();
544
545 if (ds != nullptr && !cols.empty())
547
548 jittedFilter->SetFilter(
549 std::unique_ptr<RFilterBase>(new F_t(std::forward<F>(f), cols, prevNode, colRegister, jittedFilter->GetName())));
550}
551
552namespace DefineTypes {
553struct RDefineTag {};
554struct RDefinePerSampleTag {};
555}
556
557template <typename F>
558auto MakeDefineNode(DefineTypes::RDefineTag, std::string_view name, std::string_view dummyType, F &&f,
559 const ColumnNames_t &cols, RColumnRegister &colRegister, RLoopManager &lm)
560{
561 return std::unique_ptr<RDefineBase>(new RDefine<std::decay_t<F>, ExtraArgsForDefine::None>(
562 name, dummyType, std::forward<F>(f), cols, colRegister, lm));
563}
564
565template <typename F>
566auto MakeDefineNode(DefineTypes::RDefinePerSampleTag, std::string_view name, std::string_view dummyType, F &&f,
567 const ColumnNames_t &, RColumnRegister &, RLoopManager &lm)
568{
569 return std::unique_ptr<RDefineBase>(
570 new RDefinePerSample<std::decay_t<F>>(name, dummyType, std::forward<F>(f), lm));
571}
572
573// Build a RDefine or a RDefinePerSample object and attach it to an existing RJittedDefine
574// This function is meant to be called by jitted code right before starting the event loop.
575// If colsPtr is null, build a RDefinePerSample (it has no input columns), otherwise a RDefine.
576template <typename RDefineTypeTag, typename F>
577void JitDefineHelper(F &&f, const ColumnNames_t &cols, RColumnRegister &colRegister,
579{
580
581 if (!jittedDefine) {
582 // The branch of the computation graph that needed this jitted code went out of scope between the type
583 // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
584 return;
585 }
586
587 using Callable_t = std::decay_t<F>;
588 using ColTypes_t = typename TTraits::CallableTraits<Callable_t>::arg_types;
589
590 auto ds = lm.GetDataSource();
591 if (ds != nullptr && !cols.empty())
593
594 // will never actually be used (trumped by jittedDefine->GetTypeName()), but we set it to something meaningful
595 // to help devs debugging
596 const auto dummyType = "jittedCol_t";
597 // use unique_ptr<RDefineBase> instead of make_unique<NewCol_t> to reduce jit/compile-times
598 std::unique_ptr<RDefineBase> newCol{
599 MakeDefineNode(RDefineTypeTag{}, jittedDefine->GetName(), dummyType, std::forward<F>(f), cols, colRegister, lm)};
600 jittedDefine->SetDefine(std::move(newCol));
601}
602
603template <bool IsSingleColumn, typename F>
604void JitVariationHelper(F &&f, const ColumnNames_t &inputColNames, RColumnRegister &colRegister,
606 const ColumnNames_t &variedColNames, const ColumnNames_t &variationTags) noexcept
607{
608
609 if (!jittedVariation) {
610 // The branch of the computation graph that needed this jitted variation went out of scope between the type
611 // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
612 return;
613 }
614
615 using Callable_t = std::decay_t<F>;
616 using ColTypes_t = typename TTraits::CallableTraits<Callable_t>::arg_types;
617
618 auto ds = lm.GetDataSource();
619 if (ds != nullptr && !inputColNames.empty())
621
622 // use unique_ptr<RDefineBase> instead of make_unique<NewCol_t> to reduce jit/compile-times
623 std::unique_ptr<RVariationBase> newVariation{new RVariation<std::decay_t<F>, IsSingleColumn>(
624 variedColNames, jittedVariation->GetVariationName(), std::forward<F>(f), variationTags,
625 jittedVariation->GetTypeName(), colRegister, lm, inputColNames)};
626 jittedVariation->SetVariation(std::move(newVariation));
627}
628
629/// Convenience function invoked by jitted code to build action nodes at runtime
630template <typename ActionTag, typename... ColTypes, typename HelperArgType>
631void CallBuildAction(const ColumnNames_t &cols, RColumnRegister &colRegister, ROOT::Detail::RDF::RLoopManager &lm,
632 RJittedAction *jittedAction, unsigned int nSlots,
633 std::shared_ptr<HelperArgType> *helperArg) noexcept
634{
635 if (!jittedAction) {
636 // The branch of the computation graph that needed this jitted variation went out of scope between the type
637 // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
638 return;
639 }
640
641 using ColTypes_t = TypeList<ColTypes...>;
642 constexpr auto nColumns = ColTypes_t::list_size;
643 auto ds = lm.GetDataSource();
644 if (ds != nullptr && !cols.empty())
646
647 auto actionPtr =
649 jittedAction->SetAction(std::move(actionPtr));
650}
651
652/// The contained `type` alias is `double` if `T == RInferredType`, `U` if `T == std::container<U>`, `T` otherwise.
653template <typename T, bool Container = IsDataContainer<T>::value && !std::is_same<T, std::string>::value>
654struct RMinReturnType {
655 using type = T;
656};
657
658template <>
660 using type = double;
661};
662
663template <typename T>
664struct RMinReturnType<T, true> {
665 using type = TTraits::TakeFirstParameter_t<T>;
666};
667
668// return wrapper around f that prepends an `unsigned int slot` parameter
669template <typename R, typename F, typename... Args>
670std::function<R(unsigned int, Args...)> AddSlotParameter(F &f, TypeList<Args...>)
671{
672 return [f](unsigned int, Args... a) mutable -> R { return f(a...); };
673}
674
675template <typename ColType, typename... Rest>
676struct RNeedJittingHelper {
677 static constexpr bool value = RNeedJittingHelper<Rest...>::value;
678};
679
680template <typename... Rest>
682 static constexpr bool value = true;
683};
684
685template <typename T>
686struct RNeedJittingHelper<T> {
687 static constexpr bool value = false;
688};
689
690template <>
692 static constexpr bool value = true;
693};
694
695template <typename ...ColTypes>
696struct RNeedJitting {
697 static constexpr bool value = RNeedJittingHelper<ColTypes...>::value;
698};
699
700template <>
701struct RNeedJitting<> {
702 static constexpr bool value = false;
703};
704
705///////////////////////////////////////////////////////////////////////////////
706/// Check preconditions for RInterface::Aggregate:
707/// - the aggregator callable must have signature `U(U,T)` or `void(U&,T)`.
708/// - the merge callable must have signature `U(U,U)` or `void(std::vector<U>&)`
709template <typename R, typename Merge, typename U, typename T, typename decayedU = std::decay_t<U>,
710 typename mergeArgsNoDecay_t = typename CallableTraits<Merge>::arg_types_nodecay,
711 typename mergeArgs_t = typename CallableTraits<Merge>::arg_types,
712 typename mergeRet_t = typename CallableTraits<Merge>::ret_type>
714{
715 constexpr bool isAggregatorOk =
716 (std::is_same<R, decayedU>::value) || (std::is_same<R, void>::value && std::is_lvalue_reference<U>::value);
717 static_assert(isAggregatorOk, "aggregator function must have signature `U(U,T)` or `void(U&,T)`");
718 constexpr bool isMergeOk =
719 (std::is_same<TypeList<decayedU, decayedU>, mergeArgs_t>::value && std::is_same<decayedU, mergeRet_t>::value) ||
720 (std::is_same<TypeList<std::vector<decayedU> &>, mergeArgsNoDecay_t>::value &&
721 std::is_same<void, mergeRet_t>::value);
722 static_assert(isMergeOk, "merge function must have signature `U(U,U)` or `void(std::vector<U>&)`");
723}
724
725///////////////////////////////////////////////////////////////////////////////
726/// This overload of CheckAggregate is called when the aggregator takes more than two arguments
727template <typename R, typename T>
728void CheckAggregate(T)
729{
730 static_assert(sizeof(T) == 0, "aggregator function must take exactly two arguments");
731}
732
733///////////////////////////////////////////////////////////////////////////////
734/// Check as many template parameters were passed as the number of column names, throw if this is not the case.
735void CheckTypesAndPars(unsigned int nTemplateParams, unsigned int nColumnNames);
736
737/// Return local BranchNames or default BranchNames according to which one should be used
738const ColumnNames_t SelectColumns(unsigned int nArgs, const ColumnNames_t &bl, const ColumnNames_t &defBl);
739
740/// Check whether column names refer to a valid branch of a TTree or have been `Define`d. Return invalid column names.
741ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, const RColumnRegister &definedCols,
742 const ColumnNames_t &dataSourceColumns);
743
744/// Returns the list of Filters defined in the whole graph
745std::vector<std::string> GetFilterNames(const std::shared_ptr<RLoopManager> &loopManager);
746
747/// Returns the list of Filters defined in the branch
748template <typename NodeType>
749std::vector<std::string> GetFilterNames(const std::shared_ptr<NodeType> &node)
750{
751 std::vector<std::string> filterNames;
752 node->AddFilterName(filterNames);
753 return filterNames;
754}
755
756struct ParsedTreePath {
757 std::string fTreeName;
758 std::string fDirName;
759};
760
762
763// Check if a condition is true for all types
764template <bool...>
765struct TBoolPack;
766
767template <bool... bs>
768using IsTrueForAllImpl_t = typename std::is_same<TBoolPack<bs..., true>, TBoolPack<true, bs...>>;
769
770template <bool... Conditions>
771struct TEvalAnd {
772 static constexpr bool value = IsTrueForAllImpl_t<Conditions...>::value;
773};
774
775// Check if a class is a specialisation of stl containers templates
776// clang-format off
777
778template <typename>
779struct IsList_t : std::false_type {};
780
781template <typename T>
782struct IsList_t<std::list<T>> : std::true_type {};
783
784template <typename>
785struct IsDeque_t : std::false_type {};
786
787template <typename T>
788struct IsDeque_t<std::deque<T>> : std::true_type {};
789// clang-format on
790
791void CheckForDuplicateSnapshotColumns(const ColumnNames_t &cols);
792
794
795template <typename T>
796struct InnerValueType {
797 using type = T; // fallback for when T is not a nested RVec
798};
799
800template <typename Elem>
801struct InnerValueType<ROOT::VecOps::RVec<ROOT::VecOps::RVec<Elem>>> {
802 using type = Elem;
803};
804
805template <typename T>
807
808std::pair<std::vector<std::string>, std::vector<std::string>>
810 std::vector<std::string> &&colsWithAliases);
811
812void RemoveDuplicates(ColumnNames_t &columnNames);
813void RemoveRNTupleSubFields(ColumnNames_t &columnNames);
814
815} // namespace RDF
816} // namespace Internal
817
818namespace Detail {
819namespace RDF {
820
821/// The aliased type is `double` if `T == RInferredType`, `U` if `T == container<U>`, `T` otherwise.
822template <typename T>
823using MinReturnType_t = typename RDFInternal::RMinReturnType<T>::type;
824
825template <typename T>
827
828template <typename T>
830
831} // namespace RDF
832} // namespace Detail
833} // namespace ROOT
834
835/// \endcond
836
837#endif
#define f(i)
Definition RSha256.hxx:104
#define g(i)
Definition RSha256.hxx:105
#define a(i)
Definition RSha256.hxx:99
#define h(i)
Definition RSha256.hxx:106
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Int_t gErrorIgnoreLevel
errors with level below this value will be ignored. Default is kUnset.
Definition TError.cxx:33
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:110
A wrapper around a concrete RDefine, which forwards all calls to it RJittedDefine is a placeholder th...
A wrapper around a concrete RFilter, which forwards all calls to it RJittedFilter is the type of the ...
The head node of a RDF computation graph.
A histogram data structure to bin data along multiple dimensions.
A histogram for aggregation of data along multiple dimensions.
Definition RHist.hxx:64
A binder for user-defined columns, variations and aliases.
RDataSource defines an API that RDataFrame can use to read arbitrary data formats.
The public interface to the RDataFrame federation of classes.
const_iterator end() const
A "std::vector"-like collection of values implementing handy operation to analyse them.
Definition RVec.hxx:1524
A TTree represents a columnar dataset.
Definition TTree.h:89
#define F(x, y, z)
const ColumnNames_t SelectColumns(unsigned int nRequiredNames, const ColumnNames_t &names, const ColumnNames_t &defaultNames)
Choose between local column names or default column names, throw in case of errors.
void CheckForNoVariations(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister)
Throw if the column has systematic variations attached.
ParsedTreePath ParseTreePath(std::string_view fullTreeName)
std::shared_ptr< RJittedDefine > BookDefinePerSampleJit(std::string_view name, std::string_view expression, RLoopManager &lm, const RColumnRegister &colRegister)
Book the jitting of a DefinePerSample call.
void CheckValidCppVarName(std::string_view var, const std::string &where)
void RemoveDuplicates(ColumnNames_t &columnNames)
ColumnNames_t GetValidatedColumnNames(RLoopManager &lm, const unsigned int nColumns, const ColumnNames_t &columns, const RColumnRegister &colRegister, RDataSource *ds)
Given the desired number of columns and the user-provided list of columns:
std::shared_ptr< RNodeBase > UpcastNode(std::shared_ptr< RNodeBase > ptr)
void CheckSnapshotOptionsFormatCompatibility(const ROOT::RDF::RSnapshotOptions &opts)
void CheckForDefinition(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister, const ColumnNames_t &dataSourceColumns)
Throw if column definedColView is not already there.
std::vector< std::string > GetFilterNames(const std::shared_ptr< RLoopManager > &loopManager)
std::string PrettyPrintAddr(const void *const addr)
std::shared_ptr< RDFDetail::RJittedFilter > BookFilterJit(std::shared_ptr< RDFDetail::RNodeBase > prevNode, std::string_view name, std::string_view expression, const RColumnRegister &colRegister, TTree *tree, RDataSource *ds)
Book the jitting of a Filter call.
std::string JitBuildAction(const ColumnNames_t &cols, const std::type_info &helperArgType, const std::type_info &at, TTree *tree, const unsigned int nSlots, const RColumnRegister &colRegister, RDataSource *ds, const bool vector2RVec)
void CheckTypesAndPars(unsigned int nTemplateParams, unsigned int nColumnNames)
std::string DemangleTypeIdName(const std::type_info &typeInfo)
bool AtLeastOneEmptyString(const std::vector< std::string_view > strings)
std::unique_ptr< ROOT::Detail::RDF::RColumnReaderBase > CreateColumnReader(ROOT::RDF::RDataSource &ds, unsigned int slot, std::string_view col, const std::type_info &tid, TTreeReader *treeReader)
Definition RDFUtils.cxx:684
std::pair< std::vector< std::string >, std::vector< std::string > > AddSizeBranches(ROOT::RDF::RDataSource *ds, std::vector< std::string > &&colsWithoutAliases, std::vector< std::string > &&colsWithAliases)
Return copies of colsWithoutAliases and colsWithAliases with size branches for variable-sized array b...
void RemoveRNTupleSubFields(ColumnNames_t &columnNames)
ColumnNames_t FilterArraySizeColNames(const ColumnNames_t &columnNames, const std::string &action)
Take a list of column names, return that list with entries starting by '#' filtered out.
std::shared_ptr< RJittedVariation > BookVariationJit(const std::vector< std::string > &colNames, std::string_view variationName, const std::vector< std::string > &variationTags, std::string_view expression, RLoopManager &lm, RDataSource *ds, const RColumnRegister &colRegister, bool isSingleColumn)
Book the jitting of a Vary call.
std::vector< std::string > GetValidatedArgTypes(const ColumnNames_t &colNames, const RColumnRegister &colRegister, TTree *tree, RDataSource *ds, const std::string &context, bool vector2RVec)
void CheckForDuplicateSnapshotColumns(const ColumnNames_t &cols)
ColumnNames_t ConvertRegexToColumns(const ColumnNames_t &colNames, std::string_view columnNameRegexp, std::string_view callerName)
ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, const RColumnRegister &definedCols, const ColumnNames_t &dataSourceColumns)
unsigned int & NThreadPerTH3()
Obtain or set the number of threads that will share a clone of a thread-safe 3D histogram.
Definition RDFUtils.cxx:76
void CheckForRedefinition(const std::string &where, std::string_view definedColView, const RColumnRegister &colRegister, const ColumnNames_t &dataSourceColumns)
Throw if column definedColView is already there.
std::shared_ptr< RJittedDefine > BookDefineJit(std::string_view name, std::string_view expression, RLoopManager &lm, RDataSource *ds, const RColumnRegister &colRegister)
Book the jitting of a Define call.
ROOT type_traits extensions.
Bool_t IsImplicitMTEnabled()
Returns true if the implicit multi-threading in ROOT is enabled.
Definition TROOT.cxx:600
A collection of options to steer the creation of the dataset on disk through Snapshot().
Lightweight storage for a collection of types.