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