Logo ROOT  
Reference Guide
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 "RColumnRegister.hxx"
15#include <ROOT/RDF/RAction.hxx>
16#include <ROOT/RDF/ActionHelpers.hxx> // for BuildAction
18#include <ROOT/RDF/RDefine.hxx>
20#include <ROOT/RDF/RFilter.hxx>
21#include <ROOT/RDF/Utils.hxx>
27#include <ROOT/RStringView.hxx>
29#include <ROOT/TypeTraits.hxx>
30#include <TError.h> // gErrorIgnoreLevel
31#include <TH1.h>
32#include <TROOT.h> // IsImplicitMTEnabled
33
34#include <deque>
35#include <functional>
36#include <map>
37#include <memory>
38#include <string>
39#include <type_traits>
40#include <typeinfo>
41#include <vector>
42#include <unordered_map>
43
44class TObjArray;
45class TTree;
46namespace ROOT {
47namespace Detail {
48namespace RDF {
49class RNodeBase;
50}
51}
52namespace RDF {
53template <typename T>
54class RResultPtr;
55template<typename T, typename V>
56class RInterface;
58class RDataSource;
59} // namespace RDF
60
61} // namespace ROOT
62
63/// \cond HIDDEN_SYMBOLS
64
65namespace ROOT {
66namespace Internal {
67namespace RDF {
68using namespace ROOT::Detail::RDF;
69using namespace ROOT::RDF;
70namespace TTraits = ROOT::TypeTraits;
71
73
74std::string DemangleTypeIdName(const std::type_info &typeInfo);
75
77ConvertRegexToColumns(const ColumnNames_t &colNames, std::string_view columnNameRegexp, std::string_view callerName);
78
79/// An helper object that sets and resets gErrorIgnoreLevel via RAII.
80class RIgnoreErrorLevelRAII {
81private:
82 int fCurIgnoreErrorLevel = gErrorIgnoreLevel;
83
84public:
85 RIgnoreErrorLevelRAII(int errorIgnoreLevel) { gErrorIgnoreLevel = errorIgnoreLevel; }
86 ~RIgnoreErrorLevelRAII() { gErrorIgnoreLevel = fCurIgnoreErrorLevel; }
87};
88
89/****** BuildAction overloads *******/
90
91// clang-format off
92/// This namespace defines types to be used for tag dispatching in RInterface.
93namespace ActionTags {
94struct Histo1D{};
95struct Histo2D{};
96struct Histo3D{};
97struct HistoND{};
98struct Graph{};
99struct GraphAsymmErrors{};
100struct Profile1D{};
101struct Profile2D{};
102struct Min{};
103struct Max{};
104struct Sum{};
105struct Mean{};
106struct Fill{};
107struct StdDev{};
108struct Display{};
109struct Snapshot{};
110struct Book{};
111}
112// clang-format on
113
114template <typename T, bool ISV6HISTO = std::is_base_of<TH1, std::decay_t<T>>::value>
115struct HistoUtils {
116 static void SetCanExtendAllAxes(T &h) { h.SetCanExtend(::TH1::kAllAxes); }
117 static bool HasAxisLimits(T &h)
118 {
119 auto xaxis = h.GetXaxis();
120 return !(xaxis->GetXmin() == 0. && xaxis->GetXmax() == 0.);
121 }
122};
123
124template <typename T>
125struct HistoUtils<T, false> {
126 static void SetCanExtendAllAxes(T &) {}
127 static bool HasAxisLimits(T &) { return true; }
128};
129
130// Generic filling (covers Histo2D, Histo3D, HistoND, Profile1D and Profile2D actions, with and without weights)
131template <typename... ColTypes, typename ActionTag, typename ActionResultType, typename PrevNodeType>
132std::unique_ptr<RActionBase>
133BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &h, const unsigned int nSlots,
134 std::shared_ptr<PrevNodeType> prevNode, ActionTag, const RColumnRegister &colRegister)
135{
136 using Helper_t = FillHelper<ActionResultType>;
137 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
138 return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister);
139}
140
141// Histo1D filling (must handle the special case of distinguishing FillHelper and BufferedFillHelper
142template <typename... ColTypes, typename PrevNodeType>
143std::unique_ptr<RActionBase>
144BuildAction(const ColumnNames_t &bl, const std::shared_ptr<::TH1D> &h, const unsigned int nSlots,
145 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Histo1D, const RColumnRegister &colRegister)
146{
147 auto hasAxisLimits = HistoUtils<::TH1D>::HasAxisLimits(*h);
148
149 if (hasAxisLimits) {
150 using Helper_t = FillHelper<::TH1D>;
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 } else {
154 using Helper_t = BufferedFillHelper;
155 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
156 return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), colRegister);
157 }
158}
159
160template <typename... ColTypes, typename PrevNodeType>
161std::unique_ptr<RActionBase>
162BuildAction(const ColumnNames_t &bl, const std::shared_ptr<TGraph> &g, const unsigned int nSlots,
163 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Graph, const RColumnRegister &colRegister)
164{
165 using Helper_t = FillTGraphHelper;
166 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
167 return std::make_unique<Action_t>(Helper_t(g, nSlots), bl, std::move(prevNode), colRegister);
168}
169
170template <typename... ColTypes, typename PrevNodeType>
171std::unique_ptr<RActionBase>
172BuildAction(const ColumnNames_t &bl, const std::shared_ptr<TGraphAsymmErrors> &g, const unsigned int nSlots,
173 std::shared_ptr<PrevNodeType> prevNode, ActionTags::GraphAsymmErrors, const RColumnRegister &colRegister)
174{
175 using Helper_t = FillTGraphAsymmErrorsHelper;
176 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
177 return std::make_unique<Action_t>(Helper_t(g, nSlots), bl, std::move(prevNode), colRegister);
178}
179
180// Min action
181template <typename ColType, typename PrevNodeType, typename ActionResultType>
182std::unique_ptr<RActionBase>
183BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &minV, const unsigned int nSlots,
184 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Min, const RColumnRegister &colRegister)
185{
186 using Helper_t = MinHelper<ActionResultType>;
187 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColType>>;
188 return std::make_unique<Action_t>(Helper_t(minV, nSlots), bl, std::move(prevNode), colRegister);
189}
190
191// Max action
192template <typename ColType, typename PrevNodeType, typename ActionResultType>
193std::unique_ptr<RActionBase>
194BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &maxV, const unsigned int nSlots,
195 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Max, const RColumnRegister &colRegister)
196{
197 using Helper_t = MaxHelper<ActionResultType>;
198 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColType>>;
199 return std::make_unique<Action_t>(Helper_t(maxV, nSlots), bl, std::move(prevNode), colRegister);
200}
201
202// Sum action
203template <typename ColType, typename PrevNodeType, typename ActionResultType>
204std::unique_ptr<RActionBase>
205BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &sumV, const unsigned int nSlots,
206 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Sum, const RColumnRegister &colRegister)
207{
208 using Helper_t = SumHelper<ActionResultType>;
209 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColType>>;
210 return std::make_unique<Action_t>(Helper_t(sumV, nSlots), bl, std::move(prevNode), colRegister);
211}
212
213// Mean action
214template <typename ColType, typename PrevNodeType>
215std::unique_ptr<RActionBase>
216BuildAction(const ColumnNames_t &bl, const std::shared_ptr<double> &meanV, const unsigned int nSlots,
217 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Mean, const RColumnRegister &colRegister)
218{
219 using Helper_t = MeanHelper;
220 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColType>>;
221 return std::make_unique<Action_t>(Helper_t(meanV, nSlots), bl, std::move(prevNode), colRegister);
222}
223
224// Standard Deviation action
225template <typename ColType, typename PrevNodeType>
226std::unique_ptr<RActionBase>
227BuildAction(const ColumnNames_t &bl, const std::shared_ptr<double> &stdDeviationV, const unsigned int nSlots,
228 std::shared_ptr<PrevNodeType> prevNode, ActionTags::StdDev, const RColumnRegister &colRegister)
229{
230 using Helper_t = StdDevHelper;
231 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColType>>;
232 return std::make_unique<Action_t>(Helper_t(stdDeviationV, nSlots), bl, prevNode, colRegister);
233}
234
235// Display action
236template <typename... ColTypes, typename PrevNodeType>
237std::unique_ptr<RActionBase> BuildAction(const ColumnNames_t &bl, const std::shared_ptr<RDisplay> &d,
238 const unsigned int, std::shared_ptr<PrevNodeType> prevNode,
239 ActionTags::Display, const RDFInternal::RColumnRegister &colRegister)
240{
241 using Helper_t = DisplayHelper<PrevNodeType>;
242 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
243 return std::make_unique<Action_t>(Helper_t(d, prevNode), bl, prevNode, colRegister);
244}
245
246struct SnapshotHelperArgs {
247 std::string fFileName;
248 std::string fDirName;
249 std::string fTreeName;
250 std::vector<std::string> fOutputColNames;
252};
253
254// Snapshot action
255template <typename... ColTypes, typename PrevNodeType>
256std::unique_ptr<RActionBase>
257BuildAction(const ColumnNames_t &colNames, const std::shared_ptr<SnapshotHelperArgs> &snapHelperArgs,
258 const unsigned int nSlots, std::shared_ptr<PrevNodeType> prevNode, ActionTags::Snapshot,
259 const RColumnRegister &colRegister)
260{
261 const auto &filename = snapHelperArgs->fFileName;
262 const auto &dirname = snapHelperArgs->fDirName;
263 const auto &treename = snapHelperArgs->fTreeName;
264 const auto &outputColNames = snapHelperArgs->fOutputColNames;
265 const auto &options = snapHelperArgs->fOptions;
266
267 auto makeIsDefine = [&] {
268 std::vector<bool> isDef;
269 isDef.reserve(sizeof...(ColTypes));
270 for (auto i = 0u; i < sizeof...(ColTypes); ++i)
271 isDef[i] = colRegister.HasName(colNames[i]);
272 return isDef;
273 };
274 std::vector<bool> isDefine = makeIsDefine();
275
276 std::unique_ptr<RActionBase> actionPtr;
278 // single-thread snapshot
279 using Helper_t = SnapshotHelper<ColTypes...>;
280 using Action_t = RAction<Helper_t, PrevNodeType>;
281 actionPtr.reset(
282 new Action_t(Helper_t(filename, dirname, treename, colNames, outputColNames, options, std::move(isDefine)),
283 colNames, prevNode, colRegister));
284 } else {
285 // multi-thread snapshot
286 using Helper_t = SnapshotHelperMT<ColTypes...>;
287 using Action_t = RAction<Helper_t, PrevNodeType>;
288 actionPtr.reset(new Action_t(
289 Helper_t(nSlots, filename, dirname, treename, colNames, outputColNames, options, std::move(isDefine)),
290 colNames, prevNode, colRegister));
291 }
292 return actionPtr;
293}
294
295// Book with custom helper type
296template <typename... ColTypes, typename PrevNodeType, typename Helper_t>
297std::unique_ptr<RActionBase>
298BuildAction(const ColumnNames_t &bl, const std::shared_ptr<Helper_t> &h, const unsigned int /*nSlots*/,
299 std::shared_ptr<PrevNodeType> prevNode, ActionTags::Book, const RColumnRegister &colRegister)
300{
301 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<ColTypes...>>;
302 return std::make_unique<Action_t>(Helper_t(std::move(*h)), bl, std::move(prevNode), colRegister);
303}
304
305/****** end BuildAndBook ******/
306
307template <typename Filter>
308void CheckFilter(Filter &)
309{
310 using FilterRet_t = typename RDF::CallableTraits<Filter>::ret_type;
312 "filter expression returns a type that is not convertible to bool");
313}
314
315ColumnNames_t FilterArraySizeColNames(const ColumnNames_t &columnNames, const std::string &action);
316
317void CheckValidCppVarName(std::string_view var, const std::string &where);
318
319void CheckForRedefinition(const std::string &where, std::string_view definedCol, const RColumnRegister &customCols,
320 const ColumnNames_t &treeColumns, const ColumnNames_t &dataSourceColumns);
321
322void CheckForDefinition(const std::string &where, std::string_view definedColView, const RColumnRegister &customCols,
323 const ColumnNames_t &treeColumns, const ColumnNames_t &dataSourceColumns);
324
325void CheckForNoVariations(const std::string &where, std::string_view definedColView, const RColumnRegister &customCols);
326
327std::string PrettyPrintAddr(const void *const addr);
328
329std::shared_ptr<RJittedFilter> BookFilterJit(std::shared_ptr<RNodeBase> *prevNodeOnHeap, std::string_view name,
330 std::string_view expression, const ColumnNames_t &branches,
331 const RColumnRegister &customCols, TTree *tree, RDataSource *ds);
332
333std::shared_ptr<RJittedDefine> BookDefineJit(std::string_view name, std::string_view expression, RLoopManager &lm,
334 RDataSource *ds, const RColumnRegister &customCols,
335 const ColumnNames_t &branches, std::shared_ptr<RNodeBase> *prevNodeOnHeap);
336
337std::shared_ptr<RJittedDefine> BookDefinePerSampleJit(std::string_view name, std::string_view expression,
338 RLoopManager &lm, const RColumnRegister &customCols,
339 std::shared_ptr<RNodeBase> *upcastNodeOnHeap);
340
341std::shared_ptr<RJittedVariation>
342BookVariationJit(const std::vector<std::string> &colNames, std::string_view variationName,
343 const std::vector<std::string> &variationTags, std::string_view expression, RLoopManager &lm,
344 RDataSource *ds, const RColumnRegister &colRegister, const ColumnNames_t &branches,
345 std::shared_ptr<RNodeBase> *upcastNodeOnHeap);
346
347std::string JitBuildAction(const ColumnNames_t &bl, std::shared_ptr<RDFDetail::RNodeBase> *prevNode,
348 const std::type_info &art, const std::type_info &at, void *rOnHeap, TTree *tree,
349 const unsigned int nSlots, const RColumnRegister &colRegister, RDataSource *ds,
350 std::weak_ptr<RJittedAction> *jittedActionOnHeap);
351
352// Allocate a weak_ptr on the heap, return a pointer to it. The user is responsible for deleting this weak_ptr.
353// This function is meant to be used by RInterface's methods that book code for jitting.
354// The problem it solves is that we generate code to be lazily jitted with the addresses of certain objects in them,
355// and we need to check those objects are still alive when the generated code is finally jitted and executed.
356// So we pass addresses to weak_ptrs allocated on the heap to the jitted code, which is then responsible for
357// the deletion of the weak_ptr object.
358template <typename T>
359std::weak_ptr<T> *MakeWeakOnHeap(const std::shared_ptr<T> &shPtr)
360{
361 return new std::weak_ptr<T>(shPtr);
362}
363
364// Same as MakeWeakOnHeap, but create a shared_ptr that makes sure the object is definitely kept alive.
365template <typename T>
366std::shared_ptr<T> *MakeSharedOnHeap(const std::shared_ptr<T> &shPtr)
367{
368 return new std::shared_ptr<T>(shPtr);
369}
370
371bool AtLeastOneEmptyString(const std::vector<std::string_view> strings);
372
373/// Take a shared_ptr<AnyNodeType> and return a shared_ptr<RNodeBase>.
374/// This works for RLoopManager nodes as well as filters and ranges.
375std::shared_ptr<RNodeBase> UpcastNode(std::shared_ptr<RNodeBase> ptr);
376
377ColumnNames_t GetValidatedColumnNames(RLoopManager &lm, const unsigned int nColumns, const ColumnNames_t &columns,
378 const RColumnRegister &validDefines, RDataSource *ds);
379
380std::vector<std::string> GetValidatedArgTypes(const ColumnNames_t &colNames, const RColumnRegister &colRegister,
381 TTree *tree, RDataSource *ds, const std::string &context,
382 bool vector2rvec);
383
384std::vector<bool> FindUndefinedDSColumns(const ColumnNames_t &requestedCols, const ColumnNames_t &definedDSCols);
385
386template <typename T>
387void AddDSColumnsHelper(const std::string &colName, RLoopManager &lm, RDataSource &ds, RColumnRegister &colRegister)
388{
389 if (colRegister.HasName(colName) || !ds.HasColumn(colName) || lm.HasDSValuePtrs(colName))
390 return;
391
392 const auto valuePtrs = ds.GetColumnReaders<T>(colName);
393 if (!valuePtrs.empty()) {
394 // we are using the old GetColumnReaders mechanism
395 std::vector<void*> typeErasedValuePtrs(valuePtrs.begin(), valuePtrs.end());
396 lm.AddDSValuePtrs(colName, std::move(typeErasedValuePtrs));
397 }
398}
399
400/// Take list of column names that must be defined, current map of custom columns, current list of defined column names,
401/// and return a new map of custom columns (with the new datasource columns added to it)
402template <typename... ColumnTypes>
403void AddDSColumns(const std::vector<std::string> &requiredCols, RLoopManager &lm, RDataSource &ds,
404 TTraits::TypeList<ColumnTypes...>, RColumnRegister &colRegister)
405{
406 // hack to expand a template parameter pack without c++17 fold expressions.
407 using expander = int[];
408 int i = 0;
409 (void)expander{(AddDSColumnsHelper<ColumnTypes>(requiredCols[i], lm, ds, colRegister), ++i)..., 0};
410}
411
412// this function is meant to be called by the jitted code generated by BookFilterJit
413template <typename F, typename PrevNode>
414void JitFilterHelper(F &&f, const char **colsPtr, std::size_t colsSize, std::string_view name,
415 std::weak_ptr<RJittedFilter> *wkJittedFilter, std::shared_ptr<PrevNode> *prevNodeOnHeap,
416 RColumnRegister *colRegister) noexcept
417{
418 if (wkJittedFilter->expired()) {
419 // The branch of the computation graph that needed this jitted code went out of scope between the type
420 // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
421 delete wkJittedFilter;
422 delete colRegister;
423 delete prevNodeOnHeap;
424 return;
425 }
426
427 const ColumnNames_t cols(colsPtr, colsPtr + colsSize);
428 delete[] colsPtr;
429
430 const auto jittedFilter = wkJittedFilter->lock();
431
432 // mock Filter logic -- validity checks and Define-ition of RDataSource columns
433 using Callable_t = std::decay_t<F>;
435 using ColTypes_t = typename TTraits::CallableTraits<Callable_t>::arg_types;
436 constexpr auto nColumns = ColTypes_t::list_size;
437 CheckFilter(f);
438
439 auto &lm = *jittedFilter->GetLoopManagerUnchecked(); // RLoopManager must exist at this time
440 auto ds = lm.GetDataSource();
441
442 if (ds != nullptr)
443 AddDSColumns(cols, lm, *ds, ColTypes_t(), *colRegister);
444
445 jittedFilter->SetFilter(
446 std::unique_ptr<RFilterBase>(new F_t(std::forward<F>(f), cols, *prevNodeOnHeap, *colRegister, name)));
447 // colRegister points to the columns structure in the heap, created before the jitted call so that the jitter can
448 // share data after it has lazily compiled the code. Here the data has been used and the memory can be freed.
449 delete colRegister;
450 delete prevNodeOnHeap;
451 delete wkJittedFilter;
452}
453
454namespace DefineTypes {
455struct RDefineTag {};
456struct RDefinePerSampleTag {};
457}
458
459template <typename F>
460auto MakeDefineNode(DefineTypes::RDefineTag, std::string_view name, std::string_view dummyType, F &&f,
461 const ColumnNames_t &cols, RColumnRegister &colRegister, RLoopManager &lm)
462{
463 return std::unique_ptr<RDefineBase>(new RDefine<std::decay_t<F>, CustomColExtraArgs::None>(
464 name, dummyType, std::forward<F>(f), cols, colRegister, lm));
465}
466
467template <typename F>
468auto MakeDefineNode(DefineTypes::RDefinePerSampleTag, std::string_view name, std::string_view dummyType, F &&f,
469 const ColumnNames_t &, RColumnRegister &, RLoopManager &lm)
470{
471 return std::unique_ptr<RDefineBase>(
472 new RDefinePerSample<std::decay_t<F>>(name, dummyType, std::forward<F>(f), lm));
473}
474
475// Build a RDefine or a RDefinePerSample object and attach it to an existing RJittedDefine
476// This function is meant to be called by jitted code right before starting the event loop.
477// If colsPtr is null, build a RDefinePerSample (it has no input columns), otherwise a RDefine.
478template <typename RDefineTypeTag, typename F>
479void JitDefineHelper(F &&f, const char **colsPtr, std::size_t colsSize, std::string_view name, RLoopManager *lm,
480 std::weak_ptr<RJittedDefine> *wkJittedDefine, RColumnRegister *colRegister,
481 std::shared_ptr<RNodeBase> *prevNodeOnHeap) noexcept
482{
483 // a helper to delete objects allocated before jitting, so that the jitter can share data with lazily jitted code
484 auto doDeletes = [&] {
485 delete wkJittedDefine;
486 delete colRegister;
487 delete prevNodeOnHeap;
488 delete[] colsPtr;
489 };
490
491 if (wkJittedDefine->expired()) {
492 // The branch of the computation graph that needed this jitted code went out of scope between the type
493 // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
494 doDeletes();
495 return;
496 }
497
498 const ColumnNames_t cols(colsPtr, colsPtr + colsSize);
499
500 auto jittedDefine = wkJittedDefine->lock();
501
502 using Callable_t = std::decay_t<F>;
503 using ColTypes_t = typename TTraits::CallableTraits<Callable_t>::arg_types;
504
505 auto ds = lm->GetDataSource();
506 if (ds != nullptr)
507 AddDSColumns(cols, *lm, *ds, ColTypes_t(), *colRegister);
508
509 // will never actually be used (trumped by jittedDefine->GetTypeName()), but we set it to something meaningful
510 // to help devs debugging
511 const auto dummyType = "jittedCol_t";
512 // use unique_ptr<RDefineBase> instead of make_unique<NewCol_t> to reduce jit/compile-times
513 std::unique_ptr<RDefineBase> newCol{
514 MakeDefineNode(RDefineTypeTag{}, name, dummyType, std::forward<F>(f), cols, *colRegister, *lm)};
515 jittedDefine->SetDefine(std::move(newCol));
516
517 doDeletes();
518}
519
520template <typename F>
521void JitVariationHelper(F &&f, const char **colsPtr, std::size_t colsSize, const char **variedCols,
522 std::size_t variedColsSize, const char **variationTags, std::size_t variationTagsSize,
523 std::string_view variationName, RLoopManager *lm,
524 std::weak_ptr<RJittedVariation> *wkJittedVariation, RColumnRegister *colRegister,
525 std::shared_ptr<RNodeBase> *prevNodeOnHeap) noexcept
526{
527 // a helper to delete objects allocated before jitting, so that the jitter can share data with lazily jitted code
528 auto doDeletes = [&] {
529 delete[] colsPtr;
530 delete[] variedCols;
531 delete[] variationTags;
532
533 delete wkJittedVariation;
534 delete colRegister;
535 delete prevNodeOnHeap;
536 };
537
538 if (wkJittedVariation->expired()) {
539 // The branch of the computation graph that needed this jitted variation went out of scope between the type
540 // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
541 doDeletes();
542 return;
543 }
544
545 const ColumnNames_t inputColNames(colsPtr, colsPtr + colsSize);
546 std::vector<std::string> variedColNames(variedCols, variedCols + variedColsSize);
547 std::vector<std::string> tags(variationTags, variationTags + variationTagsSize);
548
549 auto jittedVariation = wkJittedVariation->lock();
550
551 using Callable_t = std::decay_t<F>;
552 using ColTypes_t = typename TTraits::CallableTraits<Callable_t>::arg_types;
553
554 auto ds = lm->GetDataSource();
555 if (ds != nullptr)
556 AddDSColumns(inputColNames, *lm, *ds, ColTypes_t(), *colRegister);
557
558 // use unique_ptr<RDefineBase> instead of make_unique<NewCol_t> to reduce jit/compile-times
559 std::unique_ptr<RVariationBase> newVariation{
560 new RVariation<std::decay_t<F>>(std::move(variedColNames), variationName, std::forward<F>(f), std::move(tags),
561 jittedVariation->GetTypeName(), *colRegister, *lm, std::move(inputColNames))};
562 jittedVariation->SetVariation(std::move(newVariation));
563
564 doDeletes();
565}
566
567/// Convenience function invoked by jitted code to build action nodes at runtime
568template <typename ActionTag, typename... ColTypes, typename PrevNodeType, typename HelperArgType>
569void CallBuildAction(std::shared_ptr<PrevNodeType> *prevNodeOnHeap, const char **colsPtr, std::size_t colsSize,
570 const unsigned int nSlots, std::shared_ptr<HelperArgType> *helperArgOnHeap,
571 std::weak_ptr<RJittedAction> *wkJittedActionOnHeap, RColumnRegister *colRegister) noexcept
572{
573 // a helper to delete objects allocated before jitting, so that the jitter can share data with lazily jitted code
574 auto doDeletes = [&] {
575 delete[] colsPtr;
576 delete helperArgOnHeap;
577 delete wkJittedActionOnHeap;
578 // colRegister must be deleted before prevNodeOnHeap because their dtor needs the RLoopManager to be alive
579 // and prevNodeOnHeap is what keeps it alive if the rest of the computation graph is already out of scope
580 delete colRegister;
581 delete prevNodeOnHeap;
582 };
583
584 if (wkJittedActionOnHeap->expired()) {
585 // The branch of the computation graph that needed this jitted variation went out of scope between the type
586 // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
587 doDeletes();
588 return;
589 }
590
591 const ColumnNames_t cols(colsPtr, colsPtr + colsSize);
592
593 auto jittedActionOnHeap = wkJittedActionOnHeap->lock();
594
595 // if we are here it means we are jitting, if we are jitting the loop manager must be alive
596 auto &prevNodePtr = *prevNodeOnHeap;
597 auto &loopManager = *prevNodePtr->GetLoopManagerUnchecked();
598 using ColTypes_t = TypeList<ColTypes...>;
599 constexpr auto nColumns = ColTypes_t::list_size;
600 auto ds = loopManager.GetDataSource();
601 if (ds != nullptr)
602 AddDSColumns(cols, loopManager, *ds, ColTypes_t(), *colRegister);
603
604 auto actionPtr = BuildAction<ColTypes...>(cols, std::move(*helperArgOnHeap), nSlots, std::move(prevNodePtr),
605 ActionTag{}, *colRegister);
606 loopManager.AddSampleCallback(actionPtr->GetSampleCallback());
607 jittedActionOnHeap->SetAction(std::move(actionPtr));
608
609 doDeletes();
610}
611
612/// The contained `type` alias is `double` if `T == RInferredType`, `U` if `T == std::container<U>`, `T` otherwise.
614struct RMinReturnType {
615 using type = T;
616};
617
618template <>
619struct RMinReturnType<RInferredType, false> {
620 using type = double;
621};
622
623template <typename T>
624struct RMinReturnType<T, true> {
625 using type = TTraits::TakeFirstParameter_t<T>;
626};
627
628// return wrapper around f that prepends an `unsigned int slot` parameter
629template <typename R, typename F, typename... Args>
630std::function<R(unsigned int, Args...)> AddSlotParameter(F &f, TypeList<Args...>)
631{
632 return [f](unsigned int, Args... a) mutable -> R { return f(a...); };
633}
634
635template <typename ColType, typename... Rest>
636struct RNeedJittingHelper {
637 static constexpr bool value = RNeedJittingHelper<Rest...>::value;
638};
639
640template <typename... Rest>
641struct RNeedJittingHelper<RInferredType, Rest...> {
642 static constexpr bool value = true;
643};
644
645template <typename T>
646struct RNeedJittingHelper<T> {
647 static constexpr bool value = false;
648};
649
650template <>
651struct RNeedJittingHelper<RInferredType> {
652 static constexpr bool value = true;
653};
654
655template <typename ...ColTypes>
656struct RNeedJitting {
657 static constexpr bool value = RNeedJittingHelper<ColTypes...>::value;
658};
659
660template <>
661struct RNeedJitting<> {
662 static constexpr bool value = false;
663};
664
665///////////////////////////////////////////////////////////////////////////////
666/// Check preconditions for RInterface::Aggregate:
667/// - the aggregator callable must have signature `U(U,T)` or `void(U&,T)`.
668/// - the merge callable must have signature `U(U,U)` or `void(std::vector<U>&)`
669template <typename R, typename Merge, typename U, typename T, typename decayedU = std::decay_t<U>,
670 typename mergeArgsNoDecay_t = typename CallableTraits<Merge>::arg_types_nodecay,
671 typename mergeArgs_t = typename CallableTraits<Merge>::arg_types,
672 typename mergeRet_t = typename CallableTraits<Merge>::ret_type>
673void CheckAggregate(TypeList<U, T>)
674{
675 constexpr bool isAggregatorOk =
677 static_assert(isAggregatorOk, "aggregator function must have signature `U(U,T)` or `void(U&,T)`");
678 constexpr bool isMergeOk =
679 (std::is_same<TypeList<decayedU, decayedU>, mergeArgs_t>::value && std::is_same<decayedU, mergeRet_t>::value) ||
680 (std::is_same<TypeList<std::vector<decayedU> &>, mergeArgsNoDecay_t>::value &&
682 static_assert(isMergeOk, "merge function must have signature `U(U,U)` or `void(std::vector<U>&)`");
683}
684
685///////////////////////////////////////////////////////////////////////////////
686/// This overload of CheckAggregate is called when the aggregator takes more than two arguments
687template <typename R, typename T>
688void CheckAggregate(T)
689{
690 static_assert(sizeof(T) == 0, "aggregator function must take exactly two arguments");
691}
692
693///////////////////////////////////////////////////////////////////////////////
694/// Check as many template parameters were passed as the number of column names, throw if this is not the case.
695void CheckTypesAndPars(unsigned int nTemplateParams, unsigned int nColumnNames);
696
697/// Return local BranchNames or default BranchNames according to which one should be used
698const ColumnNames_t SelectColumns(unsigned int nArgs, const ColumnNames_t &bl, const ColumnNames_t &defBl);
699
700/// Check whether column names refer to a valid branch of a TTree or have been `Define`d. Return invalid column names.
701ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, const ColumnNames_t &datasetColumns,
702 const RColumnRegister &definedCols, const ColumnNames_t &dataSourceColumns);
703
704/// Returns the list of Filters defined in the whole graph
705std::vector<std::string> GetFilterNames(const std::shared_ptr<RLoopManager> &loopManager);
706
707/// Returns the list of Filters defined in the branch
708template <typename NodeType>
709std::vector<std::string> GetFilterNames(const std::shared_ptr<NodeType> &node)
710{
711 std::vector<std::string> filterNames;
712 node->AddFilterName(filterNames);
713 return filterNames;
714}
715
716struct ParsedTreePath {
717 std::string fTreeName;
718 std::string fDirName;
719};
720
721ParsedTreePath ParseTreePath(std::string_view fullTreeName);
722
723// Check if a condition is true for all types
724template <bool...>
725struct TBoolPack;
726
727template <bool... bs>
728using IsTrueForAllImpl_t = typename std::is_same<TBoolPack<bs..., true>, TBoolPack<true, bs...>>;
729
730template <bool... Conditions>
731struct TEvalAnd {
732 static constexpr bool value = IsTrueForAllImpl_t<Conditions...>::value;
733};
734
735// Check if a class is a specialisation of stl containers templates
736// clang-format off
737
738template <typename>
739struct IsList_t : std::false_type {};
740
741template <typename T>
742struct IsList_t<std::list<T>> : std::true_type {};
743
744template <typename>
745struct IsDeque_t : std::false_type {};
746
747template <typename T>
748struct IsDeque_t<std::deque<T>> : std::true_type {};
749// clang-format on
750
752
753void TriggerRun(ROOT::RDF::RNode &node);
754
755template <typename T>
756struct InnerValueType {
757 using type = T; // fallback for when T is not a nested RVec
758};
759
760template <typename Elem>
761struct InnerValueType<ROOT::VecOps::RVec<ROOT::VecOps::RVec<Elem>>> {
762 using type = Elem;
763};
764
765template <typename T>
766using InnerValueType_t = typename InnerValueType<T>::type;
767
768} // namespace RDF
769} // namespace Internal
770
771namespace Detail {
772namespace RDF {
773
774/// The aliased type is `double` if `T == RInferredType`, `U` if `T == container<U>`, `T` otherwise.
775template <typename T>
776using MinReturnType_t = typename RDFInternal::RMinReturnType<T>::type;
777
778template <typename T>
779using MaxReturnType_t = MinReturnType_t<T>;
780
781template <typename T>
782using SumReturnType_t = MinReturnType_t<T>;
783
784} // namespace RDF
785} // namespace Detail
786} // namespace ROOT
787
788/// \endcond
789
790#endif
#define d(i)
Definition: RSha256.hxx:102
#define f(i)
Definition: RSha256.hxx:104
#define h(i)
Definition: RSha256.hxx:106
#define R(a, b, c, d, e, f, g, h, i)
Definition: RSha256.hxx:110
Int_t gErrorIgnoreLevel
Definition: TError.cxx:34
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 g
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
The head node of a RDF computation graph.
void AddDSValuePtrs(const std::string &col, const std::vector< void * > ptrs)
RDataSource * GetDataSource() const
bool HasDSValuePtrs(const std::string &col) const
RLoopManager * GetLoopManagerUnchecked() final
A binder for user-defined columns and aliases.
RDataSource defines an API that RDataFrame can use to read arbitrary data formats.
virtual bool HasColumn(std::string_view colName) const =0
Checks if the dataset has a certain column.
std::vector< T ** > GetColumnReaders(std::string_view columnName)
Called at most once per column by RDF.
The public interface to the RDataFrame federation of classes.
Definition: RInterface.hxx:104
A "std::vector"-like collection of values implementing handy operation to analyse them.
Definition: RVec.hxx:1439
@ kAllAxes
Definition: TH1.h:75
An array of TObjects.
Definition: TObjArray.h:31
A TTree represents a columnar dataset.
Definition: TTree.h:79
R Sum(const RVec< T > &v, const R zero=R(0))
Sum elements of an RVec.
Definition: RVec.hxx:1861
RVec< T > Filter(const RVec< T > &v, F &&f)
Create a new collection with the elements passing the filter expressed by the predicate.
Definition: RVec.hxx:2070
basic_string_view< char > string_view
#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.
ParsedTreePath ParseTreePath(std::string_view fullTreeName)
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, const ColumnNames_t &branches, std::shared_ptr< RNodeBase > *upcastNodeOnHeap)
Book the jitting of a Vary call.
void CheckValidCppVarName(std::string_view var, const std::string &where)
std::shared_ptr< RNodeBase > UpcastNode(std::shared_ptr< RNodeBase > ptr)
ColumnNames_t GetValidatedColumnNames(RLoopManager &lm, const unsigned int nColumns, const ColumnNames_t &columns, const RColumnRegister &customColumns, RDataSource *ds)
Given the desired number of columns and the user-provided list of columns:
std::vector< std::string > GetFilterNames(const std::shared_ptr< RLoopManager > &loopManager)
std::string PrettyPrintAddr(const void *const addr)
std::string JitBuildAction(const ColumnNames_t &cols, std::shared_ptr< RDFDetail::RNodeBase > *prevNode, const std::type_info &helperArgType, const std::type_info &at, void *helperArgOnHeap, TTree *tree, const unsigned int nSlots, const RColumnRegister &customCols, RDataSource *ds, std::weak_ptr< RJittedAction > *jittedActionOnHeap)
ColumnNames_t GetTopLevelBranchNames(TTree &t)
Get all the top-level branches names, including the ones of the friend trees.
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)
void CheckForDefinition(const std::string &where, std::string_view definedColView, const RColumnRegister &customCols, const ColumnNames_t &treeColumns, const ColumnNames_t &dataSourceColumns)
Throw if column definedColView is not already there.
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< RJittedDefine > BookDefinePerSampleJit(std::string_view name, std::string_view expression, RLoopManager &lm, const RColumnRegister &customCols, std::shared_ptr< RNodeBase > *upcastNodeOnHeap)
Book the jitting of a DefinePerSample call.
void CheckForRedefinition(const std::string &where, std::string_view definedColView, const RColumnRegister &customCols, const ColumnNames_t &treeColumns, const ColumnNames_t &dataSourceColumns)
Throw if column definedColView is already there.
void CheckForDuplicateSnapshotColumns(const ColumnNames_t &cols)
ColumnNames_t ConvertRegexToColumns(const ColumnNames_t &colNames, std::string_view columnNameRegexp, std::string_view callerName)
std::vector< bool > FindUndefinedDSColumns(const ColumnNames_t &requestedCols, const ColumnNames_t &definedCols)
Return a bitset each element of which indicates whether the corresponding element in selectedColumns ...
std::shared_ptr< RJittedDefine > BookDefineJit(std::string_view name, std::string_view expression, RLoopManager &lm, RDataSource *ds, const RColumnRegister &customCols, const ColumnNames_t &branches, std::shared_ptr< RNodeBase > *upcastNodeOnHeap)
Book the jitting of a Define call.
std::vector< std::string > GetValidatedArgTypes(const ColumnNames_t &colNames, const RColumnRegister &colRegister, TTree *tree, RDataSource *ds, const std::string &context, bool vector2rvec)
void CheckForNoVariations(const std::string &where, std::string_view definedColView, const RColumnRegister &customCols)
Throw if the column has systematic variations attached.
ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, const ColumnNames_t &datasetColumns, const RColumnRegister &definedCols, const ColumnNames_t &dataSourceColumns)
void TriggerRun(ROOT::RDF::RNode &node)
Trigger the execution of an RDataFrame computation graph.
std::shared_ptr< RDFDetail::RJittedFilter > BookFilterJit(std::shared_ptr< RDFDetail::RNodeBase > *prevNodeOnHeap, std::string_view name, std::string_view expression, const ColumnNames_t &branches, const RColumnRegister &customCols, TTree *tree, RDataSource *ds)
Book the jitting of a Filter call.
void(off) SmallVectorTemplateBase< T
double T(double x)
Definition: ChebyshevPol.h:34
std::vector< std::string > ColumnNames_t
Definition: Utils.hxx:35
void function(const Char_t *name_, T fun, const Char_t *docstring=0)
Definition: RExports.h:167
ROOT type_traits extensions.
Definition: TypeTraits.hxx:21
This file contains a specialised ROOT message handler to test for diagnostic in unit tests.
Bool_t IsImplicitMTEnabled()
Returns true if the implicit multi-threading in ROOT is enabled.
Definition: TROOT.cxx:558
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:208
Double_t Mean(Long64_t n, const T *a, const Double_t *w=0)
Return the weighted mean of an array a with length n.
Definition: TMath.h:1023
Short_t Min(Short_t a, Short_t b)
Definition: TMathBase.h:176
Double_t StdDev(Long64_t n, const T *a, const Double_t *w=0)
Definition: TMath.h:530
Definition: tree.py:1
A collection of options to steer the creation of the dataset on file.
Lightweight storage for a collection of types.
Definition: TypeTraits.hxx:25
auto * a
Definition: textangle.C:12