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
18#include <ROOT/RDF/RFilter.hxx>
19#include <ROOT/RDF/Utils.hxx>
25#include <ROOT/RMakeUnique.hxx>
26#include <ROOT/RStringView.hxx>
27#include <ROOT/TypeTraits.hxx>
28#include <TError.h> // gErrorIgnoreLevel
29#include <TH1.h>
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;
69
71HeadNode_t CreateSnapshotRDF(const ColumnNames_t &validCols,
72 std::string_view treeName,
73 std::string_view fileName,
74 bool isLazy,
75 RLoopManager &loopManager,
76 std::unique_ptr<RDFInternal::RActionBase> actionPtr);
77
78std::string DemangleTypeIdName(const std::type_info &typeInfo);
79
80ColumnNames_t ConvertRegexToColumns(const RDFInternal::RBookedCustomColumns &customColumns, TTree *tree,
81 ROOT::RDF::RDataSource *dataSource, std::string_view columnNameRegexp,
82 std::string_view callerName);
83
84/// An helper object that sets and resets gErrorIgnoreLevel via RAII.
85class RIgnoreErrorLevelRAII {
86private:
87 int fCurIgnoreErrorLevel = gErrorIgnoreLevel;
88
89public:
90 RIgnoreErrorLevelRAII(int errorIgnoreLevel) { gErrorIgnoreLevel = errorIgnoreLevel; }
91 RIgnoreErrorLevelRAII() { gErrorIgnoreLevel = fCurIgnoreErrorLevel; }
92};
93
94/****** BuildAction overloads *******/
95
96// clang-format off
97/// This namespace defines types to be used for tag dispatching in RInterface.
98namespace ActionTags {
99struct Histo1D{};
100struct Histo2D{};
101struct Histo3D{};
102struct Graph{};
103struct Profile1D{};
104struct Profile2D{};
105struct Min{};
106struct Max{};
107struct Sum{};
108struct Mean{};
109struct Fill{};
110struct StdDev{};
111struct Display{};
112}
113// clang-format on
114
115template <typename T, bool ISV6HISTO = std::is_base_of<TH1, T>::value>
116struct HistoUtils {
117 static void SetCanExtendAllAxes(T &h) { h.SetCanExtend(::TH1::kAllAxes); }
118 static bool HasAxisLimits(T &h)
119 {
120 auto xaxis = h.GetXaxis();
121 return !(xaxis->GetXmin() == 0. && xaxis->GetXmax() == 0.);
122 }
123};
124
125template <typename T>
126struct HistoUtils<T, false> {
127 static void SetCanExtendAllAxes(T &) {}
128 static bool HasAxisLimits(T &) { return true; }
129};
130
131// Generic filling (covers Histo2D, Histo3D, Profile1D and Profile2D actions, with and without weights)
132template <typename... BranchTypes, typename ActionTag, typename ActionResultType, typename PrevNodeType>
133std::unique_ptr<RActionBase>
134BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &h, const unsigned int nSlots,
135 std::shared_ptr<PrevNodeType> prevNode, ActionTag, RDFInternal::RBookedCustomColumns &&customColumns)
136{
137 using Helper_t = FillParHelper<ActionResultType>;
138 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<BranchTypes...>>;
139 return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), std::move(customColumns));
140}
141
142// Histo1D filling (must handle the special case of distinguishing FillParHelper and FillHelper
143template <typename... BranchTypes, typename PrevNodeType>
144std::unique_ptr<RActionBase> BuildAction(const ColumnNames_t &bl, const std::shared_ptr<::TH1D> &h,
145 const unsigned int nSlots, std::shared_ptr<PrevNodeType> prevNode,
146 ActionTags::Histo1D, RDFInternal::RBookedCustomColumns &&customColumns)
147{
148 auto hasAxisLimits = HistoUtils<::TH1D>::HasAxisLimits(*h);
149
150 if (hasAxisLimits) {
151 using Helper_t = FillParHelper<::TH1D>;
152 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<BranchTypes...>>;
153 return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), std::move(customColumns));
154 } else {
155 using Helper_t = FillHelper;
156 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<BranchTypes...>>;
157 return std::make_unique<Action_t>(Helper_t(h, nSlots), bl, std::move(prevNode), std::move(customColumns));
158 }
159}
160
161template <typename... BranchTypes, typename PrevNodeType>
162std::unique_ptr<RActionBase> BuildAction(const ColumnNames_t &bl, const std::shared_ptr<TGraph> &g,
163 const unsigned int nSlots, std::shared_ptr<PrevNodeType> prevNode,
164 ActionTags::Graph, RDFInternal::RBookedCustomColumns &&customColumns)
165{
166 using Helper_t = FillTGraphHelper;
167 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<BranchTypes...>>;
168 return std::make_unique<Action_t>(Helper_t(g, nSlots), bl, std::move(prevNode), std::move(customColumns));
169}
170
171// Min action
172template <typename BranchType, typename PrevNodeType, typename ActionResultType>
173std::unique_ptr<RActionBase> BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &minV,
174 const unsigned int nSlots, std::shared_ptr<PrevNodeType> prevNode,
176{
177 using Helper_t = MinHelper<ActionResultType>;
178 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<BranchType>>;
179 return std::make_unique<Action_t>(Helper_t(minV, nSlots), bl, std::move(prevNode), std::move(customColumns));
180}
181
182// Max action
183template <typename BranchType, typename PrevNodeType, typename ActionResultType>
184std::unique_ptr<RActionBase> BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &maxV,
185 const unsigned int nSlots, std::shared_ptr<PrevNodeType> prevNode,
187{
188 using Helper_t = MaxHelper<ActionResultType>;
189 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<BranchType>>;
190 return std::make_unique<Action_t>(Helper_t(maxV, nSlots), bl, std::move(prevNode), std::move(customColumns));
191}
192
193// Sum action
194template <typename BranchType, typename PrevNodeType, typename ActionResultType>
195std::unique_ptr<RActionBase> BuildAction(const ColumnNames_t &bl, const std::shared_ptr<ActionResultType> &sumV,
196 const unsigned int nSlots, std::shared_ptr<PrevNodeType> prevNode,
198{
199 using Helper_t = SumHelper<ActionResultType>;
200 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<BranchType>>;
201 return std::make_unique<Action_t>(Helper_t(sumV, nSlots), bl, std::move(prevNode), std::move(customColumns));
202}
203
204// Mean action
205template <typename BranchType, typename PrevNodeType>
206std::unique_ptr<RActionBase> BuildAction(const ColumnNames_t &bl, const std::shared_ptr<double> &meanV,
207 const unsigned int nSlots, std::shared_ptr<PrevNodeType> prevNode,
209{
210 using Helper_t = MeanHelper;
211 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<BranchType>>;
212 return std::make_unique<Action_t>(Helper_t(meanV, nSlots), bl, std::move(prevNode), std::move(customColumns));
213}
214
215// Standard Deviation action
216template <typename BranchType, typename PrevNodeType>
217std::unique_ptr<RActionBase> BuildAction(const ColumnNames_t &bl, const std::shared_ptr<double> &stdDeviationV,
218 const unsigned int nSlots, std::shared_ptr<PrevNodeType> prevNode,
220{
221 using Helper_t = StdDevHelper;
222 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<BranchType>>;
223 return std::make_unique<Action_t>(Helper_t(stdDeviationV, nSlots), bl, prevNode, std::move(customColumns));
224}
225
226// Display action
227template <typename... BranchTypes, typename PrevNodeType>
228std::unique_ptr<RActionBase> BuildAction(const ColumnNames_t &bl, const std::shared_ptr<RDisplay> &d,
229 const unsigned int, std::shared_ptr<PrevNodeType> prevNode,
230 ActionTags::Display, RDFInternal::RBookedCustomColumns &&customColumns)
231{
232 using Helper_t = DisplayHelper<PrevNodeType>;
233 using Action_t = RAction<Helper_t, PrevNodeType, TTraits::TypeList<BranchTypes...>>;
234 return std::make_unique<Action_t>(Helper_t(d, prevNode), bl, prevNode, std::move(customColumns));
235}
236
237/****** end BuildAndBook ******/
238
239template <typename Filter>
240void CheckFilter(Filter &)
241{
242 using FilterRet_t = typename RDF::CallableTraits<Filter>::ret_type;
243 static_assert(std::is_convertible<FilterRet_t, bool>::value,
244 "filter expression returns a type that is not convertible to bool");
245}
246
247void CheckCustomColumn(std::string_view definedCol, TTree *treePtr, const ColumnNames_t &customCols,
248 const std::map<std::string, std::string> &aliasMap, const ColumnNames_t &dataSourceColumns);
249
250std::string PrettyPrintAddr(const void *const addr);
251
252void BookFilterJit(const std::shared_ptr<RJittedFilter> &jittedFilter, std::shared_ptr<RNodeBase> *prevNodeOnHeap,
254 const std::map<std::string, std::string> &aliasMap, const ColumnNames_t &branches,
256
257std::shared_ptr<RJittedCustomColumn> BookDefineJit(std::string_view name, std::string_view expression, RLoopManager &lm,
258 RDataSource *ds, const RDFInternal::RBookedCustomColumns &customCols,
259 const ColumnNames_t &branches,
260 std::shared_ptr<RNodeBase> *prevNodeOnHeap);
261
262std::string JitBuildAction(const ColumnNames_t &bl, std::shared_ptr<RDFDetail::RNodeBase> *prevNode,
263 const std::type_info &art, const std::type_info &at, void *rOnHeap, TTree *tree,
264 const unsigned int nSlots, const RDFInternal::RBookedCustomColumns &customColumns,
265 RDataSource *ds, std::weak_ptr<RJittedAction> *jittedActionOnHeap);
266
267// Allocate a weak_ptr on the heap, return a pointer to it. The user is responsible for deleting this weak_ptr.
268// This function is meant to be used by RInterface's methods that book code for jitting.
269// The problem it solves is that we generate code to be lazily jitted with the addresses of certain objects in them,
270// and we need to check those objects are still alive when the generated code is finally jitted and executed.
271// So we pass addresses to weak_ptrs allocated on the heap to the jitted code, which is then responsible for
272// the deletion of the weak_ptr object.
273template <typename T>
274std::weak_ptr<T> *MakeWeakOnHeap(const std::shared_ptr<T> &shPtr)
275{
276 return new std::weak_ptr<T>(shPtr);
277}
278
279// Same as MakeWeakOnHeap, but create a shared_ptr that makes sure the object is definitely kept alive.
280template <typename T>
281std::shared_ptr<T> *MakeSharedOnHeap(const std::shared_ptr<T> &shPtr)
282{
283 return new std::shared_ptr<T>(shPtr);
284}
285
286bool AtLeastOneEmptyString(const std::vector<std::string_view> strings);
287
288/// Take a shared_ptr<AnyNodeType> and return a shared_ptr<RNodeBase>.
289/// This works for RLoopManager nodes as well as filters and ranges.
290std::shared_ptr<RNodeBase> UpcastNode(std::shared_ptr<RNodeBase> ptr);
291
292ColumnNames_t GetValidatedColumnNames(RLoopManager &lm, const unsigned int nColumns, const ColumnNames_t &columns,
293 const ColumnNames_t &validCustomColumns, RDataSource *ds);
294
295std::vector<std::string> GetValidatedArgTypes(const ColumnNames_t &colNames, const RBookedCustomColumns &customColumns,
296 TTree *tree, RDataSource *ds, const std::string &context,
297 bool vector2rvec);
298
299std::vector<bool> FindUndefinedDSColumns(const ColumnNames_t &requestedCols, const ColumnNames_t &definedDSCols);
300
301using ROOT::Detail::RDF::ColumnNames_t;
302
303template <typename T>
304void AddDSColumnsHelper(std::string_view name, RBookedCustomColumns &currentCols, RDataSource &ds, unsigned int nSlots)
305{
306 auto readers = ds.GetColumnReaders<T>(name);
307 auto getValue = [readers](unsigned int slot) { return *readers[slot]; };
308 using NewCol_t = RCustomColumn<decltype(getValue), CustomColExtraArgs::Slot>;
309
310 auto newCol = std::make_shared<NewCol_t>(name, ds.GetTypeName(name), std::move(getValue), ColumnNames_t{}, nSlots,
311 currentCols, /*isDSColumn=*/true);
312 currentCols.AddName(name);
313 currentCols.AddColumn(newCol, name);
314}
315
316/// Take list of column names that must be defined, current map of custom columns, current list of defined column names,
317/// and return a new map of custom columns (with the new datasource columns added to it)
318template <typename... ColumnTypes, std::size_t... S>
320AddDSColumns(const std::vector<std::string> &requiredCols, const RDFInternal::RBookedCustomColumns &currentCols,
321 RDataSource &ds, unsigned int nSlots, std::index_sequence<S...>, TTraits::TypeList<ColumnTypes...>)
322{
323
324 const auto mustBeDefined = FindUndefinedDSColumns(requiredCols, currentCols.GetNames());
325 if (std::none_of(mustBeDefined.begin(), mustBeDefined.end(), [](bool b) { return b; })) {
326 // no need to define any column
327 return currentCols;
328 } else {
329 auto newColumns(currentCols);
330
331 // hack to expand a template parameter pack without c++17 fold expressions.
332 int expander[] = {(mustBeDefined[S] ? AddDSColumnsHelper<ColumnTypes>(requiredCols[S], newColumns, ds, nSlots)
333 : /*no-op*/ ((void)0),
334 0)...,
335 0};
336 (void)expander; // avoid unused variable warnings
337 (void)nSlots; // avoid unused variable warnings
338 return newColumns;
339 }
340}
341
342// this function is meant to be called by the jitted code generated by BookFilterJit
343template <typename F, typename PrevNode>
344void JitFilterHelper(F &&f, const ColumnNames_t &cols, std::string_view name,
345 std::weak_ptr<RJittedFilter> *wkJittedFilter, std::shared_ptr<PrevNode> *prevNodeOnHeap,
347{
348 if (wkJittedFilter->expired()) {
349 // The branch of the computation graph that needed this jitted code went out of scope between the type
350 // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
351 delete wkJittedFilter;
352 // customColumns must be deleted before prevNodeOnHeap because their dtor needs the RLoopManager to be alive
353 // and prevNodeOnHeap is what keeps it alive if the rest of the computation graph is already out of scope
354 delete customColumns;
355 delete prevNodeOnHeap;
356 return;
357 }
358
359 const auto jittedFilter = wkJittedFilter->lock();
360
361 // mock Filter logic -- validity checks and Define-ition of RDataSource columns
362 using Callable_t = typename std::decay<F>::type;
364 using ColTypes_t = typename TTraits::CallableTraits<Callable_t>::arg_types;
365 constexpr auto nColumns = ColTypes_t::list_size;
366 RDFInternal::CheckFilter(f);
367
368 auto &lm = *jittedFilter->GetLoopManagerUnchecked(); // RLoopManager must exist at this time
369 auto ds = lm.GetDataSource();
370
371 auto newColumns = ds ? RDFInternal::AddDSColumns(cols, *customColumns, *ds, lm.GetNSlots(),
372 std::make_index_sequence<nColumns>(), ColTypes_t())
373 : *customColumns;
374
375 // customColumns points to the columns structure in the heap, created before the jitted call so that the jitter can
376 // share data after it has lazily compiled the code. Here the data has been used and the memory can be freed.
377 delete customColumns;
378
379 jittedFilter->SetFilter(std::make_unique<F_t>(std::forward<F>(f), cols, *prevNodeOnHeap, newColumns, name));
380 delete prevNodeOnHeap;
381 delete wkJittedFilter;
382}
383
384template <typename F>
385void JitDefineHelper(F &&f, const ColumnNames_t &cols, std::string_view name, RLoopManager *lm,
386 std::weak_ptr<RJittedCustomColumn> *wkJittedCustomCol,
387 RDFInternal::RBookedCustomColumns *customColumns, std::shared_ptr<RNodeBase> *prevNodeOnHeap)
388{
389 if (wkJittedCustomCol->expired()) {
390 // The branch of the computation graph that needed this jitted code went out of scope between the type
391 // jitting was booked and the time jitting actually happened. Nothing to do other than cleaning up.
392 delete wkJittedCustomCol;
393 // customColumns must be deleted before prevNodeOnHeap because their dtor needs the RLoopManager to be alive
394 // and prevNodeOnHeap is what keeps it alive if the rest of the computation graph is already out of scope
395 delete customColumns;
396 delete prevNodeOnHeap;
397 return;
398 }
399
400 auto jittedCustomCol = wkJittedCustomCol->lock();
401
402 using Callable_t = typename std::decay<F>::type;
404 using ColTypes_t = typename TTraits::CallableTraits<Callable_t>::arg_types;
405 constexpr auto nColumns = ColTypes_t::list_size;
406
407 auto ds = lm->GetDataSource();
408 auto newColumns = ds ? RDFInternal::AddDSColumns(cols, *customColumns, *ds, lm->GetNSlots(),
409 std::make_index_sequence<nColumns>(), ColTypes_t())
410 : *customColumns;
411
412 // customColumns points to the columns structure in the heap, created before the jitted call so that the jitter can
413 // share data after it has lazily compiled the code. Here the data has been used and the memory can be freed.
414 delete customColumns;
415 // prevNodeOnHeap only serves the purpose of keeping the RLoopManager alive so it can be accessed by
416 // customColumns' destructor in case the rest of the computation graph is gone. Can be safely deleted here.
417 delete prevNodeOnHeap;
418
419 // will never actually be used (trumped by jittedCustomCol->GetTypeName()), but we set it to something meaningful
420 // to help devs debugging
421 const auto dummyType = "jittedCol_t";
422 // use unique_ptr<RCustomColumnBase> instead of make_unique<NewCol_t> to reduce jit/compile-times
423 jittedCustomCol->SetCustomColumn(std::unique_ptr<RCustomColumnBase>(
424 new NewCol_t(name, dummyType, std::forward<F>(f), cols, lm->GetNSlots(), newColumns)));
425
426 delete wkJittedCustomCol;
427}
428
429/// Convenience function invoked by jitted code to build action nodes at runtime
430template <typename ActionTag, typename... BranchTypes, typename PrevNodeType, typename ActionResultType>
431void CallBuildAction(std::shared_ptr<PrevNodeType> *prevNodeOnHeap, const ColumnNames_t &bl, const unsigned int nSlots,
432 std::weak_ptr<ActionResultType> *wkROnHeap, std::weak_ptr<RJittedAction> *wkJittedActionOnHeap,
434{
435 if (wkROnHeap->expired()) {
436 delete wkROnHeap;
437 delete wkJittedActionOnHeap;
438 // customColumns must be deleted before prevNodeOnHeap because their dtor needs the RLoopManager to be alive
439 // and prevNodeOnHeap is what keeps it alive if the rest of the computation graph is already out of scope
440 delete customColumns;
441 delete prevNodeOnHeap;
442 return;
443 }
444
445 const auto rOnHeap = wkROnHeap->lock();
446 auto jittedActionOnHeap = wkJittedActionOnHeap->lock();
447
448 // if we are here it means we are jitting, if we are jitting the loop manager must be alive
449 auto &prevNodePtr = *prevNodeOnHeap;
450 auto &loopManager = *prevNodePtr->GetLoopManagerUnchecked();
451 using ColTypes_t = TypeList<BranchTypes...>;
452 constexpr auto nColumns = ColTypes_t::list_size;
453 auto ds = loopManager.GetDataSource();
454 auto newColumns = ds ? RDFInternal::AddDSColumns(bl, *customColumns, *ds, loopManager.GetNSlots(),
455 std::make_index_sequence<nColumns>(), ColTypes_t())
456 : *customColumns;
457
458 auto actionPtr = BuildAction<BranchTypes...>(bl, std::move(rOnHeap), nSlots, std::move(prevNodePtr), ActionTag{},
459 std::move(newColumns));
460 jittedActionOnHeap->SetAction(std::move(actionPtr));
461
462 // customColumns points to the columns structure in the heap, created before the jitted call so that the jitter can
463 // share data after it has lazily compiled the code. Here the data has been used and the memory can be freed.
464 delete customColumns;
465
466 delete wkROnHeap;
467 delete prevNodeOnHeap;
468 delete wkJittedActionOnHeap;
469}
470
471/// The contained `type` alias is `double` if `T == RInferredType`, `U` if `T == std::container<U>`, `T` otherwise.
472template <typename T, bool Container = RDFInternal::IsDataContainer<T>::value && !std::is_same<T, std::string>::value>
473struct TMinReturnType {
474 using type = T;
475};
476
477template <>
478struct TMinReturnType<RInferredType, false> {
479 using type = double;
480};
481
482template <typename T>
483struct TMinReturnType<T, true> {
484 using type = TTraits::TakeFirstParameter_t<T>;
485};
486
487// return wrapper around f that prepends an `unsigned int slot` parameter
488template <typename R, typename F, typename... Args>
489std::function<R(unsigned int, Args...)> AddSlotParameter(F &f, TypeList<Args...>)
490{
491 return [f](unsigned int, Args... a) -> R { return f(a...); };
492}
493
494template <typename BranchType, typename... Rest>
495struct TNeedJitting {
496 static constexpr bool value = TNeedJitting<Rest...>::value;
497};
498
499template <typename... Rest>
500struct TNeedJitting<RInferredType, Rest...> {
501 static constexpr bool value = true;
502};
503
504template <typename T>
505struct TNeedJitting<T> {
506 static constexpr bool value = false;
507};
508
509template <>
510struct TNeedJitting<RInferredType> {
511 static constexpr bool value = true;
512};
513
514///////////////////////////////////////////////////////////////////////////////
515/// Check preconditions for RInterface::Aggregate:
516/// - the aggregator callable must have signature `U(U,T)` or `void(U&,T)`.
517/// - the merge callable must have signature `U(U,U)` or `void(std::vector<U>&)`
519 typename mergeArgsNoDecay_t = typename CallableTraits<Merge>::arg_types_nodecay,
520 typename mergeArgs_t = typename CallableTraits<Merge>::arg_types,
521 typename mergeRet_t = typename CallableTraits<Merge>::ret_type>
522void CheckAggregate(TypeList<U, T>)
523{
524 constexpr bool isAggregatorOk =
525 (std::is_same<R, decayedU>::value) || (std::is_same<R, void>::value && std::is_lvalue_reference<U>::value);
526 static_assert(isAggregatorOk, "aggregator function must have signature `U(U,T)` or `void(U&,T)`");
527 constexpr bool isMergeOk =
528 (std::is_same<TypeList<decayedU, decayedU>, mergeArgs_t>::value && std::is_same<decayedU, mergeRet_t>::value) ||
529 (std::is_same<TypeList<std::vector<decayedU> &>, mergeArgsNoDecay_t>::value &&
530 std::is_same<void, mergeRet_t>::value);
531 static_assert(isMergeOk, "merge function must have signature `U(U,U)` or `void(std::vector<U>&)`");
532}
533
534///////////////////////////////////////////////////////////////////////////////
535/// This overload of CheckAggregate is called when the aggregator takes more than two arguments
536template <typename R, typename T>
537void CheckAggregate(T)
538{
539 static_assert(sizeof(T) == 0, "aggregator function must take exactly two arguments");
540}
541
542///////////////////////////////////////////////////////////////////////////////
543/// Check as many template parameters were passed as the number of column names, throw if this is not the case.
544void CheckTypesAndPars(unsigned int nTemplateParams, unsigned int nColumnNames);
545
546/// Return local BranchNames or default BranchNames according to which one should be used
547const ColumnNames_t SelectColumns(unsigned int nArgs, const ColumnNames_t &bl, const ColumnNames_t &defBl);
548
549/// Check whether column names refer to a valid branch of a TTree or have been `Define`d. Return invalid column names.
550ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, const ColumnNames_t &datasetColumns,
551 const ColumnNames_t &definedCols, const ColumnNames_t &dataSourceColumns);
552
554
555/// Returns the list of Filters defined in the whole graph
556std::vector<std::string> GetFilterNames(const std::shared_ptr<RLoopManager> &loopManager);
557
558/// Returns the list of Filters defined in the branch
559template <typename NodeType>
560std::vector<std::string> GetFilterNames(const std::shared_ptr<NodeType> &node)
561{
562 std::vector<std::string> filterNames;
563 node->AddFilterName(filterNames);
564 return filterNames;
565}
566
567// Check if a condition is true for all types
568template <bool...>
569struct TBoolPack;
570
571template <bool... bs>
572using IsTrueForAllImpl_t = typename std::is_same<TBoolPack<bs..., true>, TBoolPack<true, bs...>>;
573
574template <bool... Conditions>
575struct TEvalAnd {
576 static constexpr bool value = IsTrueForAllImpl_t<Conditions...>::value;
577};
578
579// Check if a class is a specialisation of stl containers templates
580// clang-format off
581
582template <typename>
583struct IsList_t : std::false_type {};
584
585template <typename T>
586struct IsList_t<std::list<T>> : std::true_type {};
587
588template <typename>
589struct IsDeque_t : std::false_type {};
590
591template <typename T>
592struct IsDeque_t<std::deque<T>> : std::true_type {};
593// clang-format on
594
595} // namespace RDF
596} // namespace Internal
597
598namespace Detail {
599namespace RDF {
600
601/// The aliased type is `double` if `T == RInferredType`, `U` if `T == container<U>`, `T` otherwise.
602template <typename T>
603using MinReturnType_t = typename RDFInternal::TMinReturnType<T>::type;
604
605template <typename T>
606using MaxReturnType_t = MinReturnType_t<T>;
607
608template <typename T>
609using SumReturnType_t = MinReturnType_t<T>;
610
611} // namespace RDF
612} // namespace Detail
613} // namespace ROOT
614
615/// \endcond
616
617#endif
double
Definition: Converters.cxx:921
#define d(i)
Definition: RSha256.hxx:102
#define b(i)
Definition: RSha256.hxx:100
#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:105
char name[80]
Definition: TGX11.cxx:109
int type
Definition: TGX11.cxx:120
typedef void((*Func_t)())
The head node of a RDF computation graph.
RDataSource * GetDataSource() const
unsigned int GetNSlots() const
Encapsulates the columns defined by the user.
ColumnNames_t GetNames() const
Returns the list of the names of the defined columns.
RDataSource defines an API that RDataFrame can use to read arbitrary data formats.
virtual std::string GetTypeName(std::string_view) const =0
Type of a column as a string, e.g.
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:89
Smart pointer for the return type of actions.
Definition: RResultPtr.hxx:72
@ kAllAxes
Definition: TH1.h:73
An array of TObjects.
Definition: TObjArray.h:37
A TTree represents a columnar dataset.
Definition: TTree.h:78
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.
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 RDFInternal::RBookedCustomColumns &customCols, TTree *tree, RDataSource *ds)
std::vector< std::string > GetValidatedArgTypes(const ColumnNames_t &colNames, const RBookedCustomColumns &customColumns, TTree *tree, RDataSource *ds, const std::string &context, bool vector2rvec)
std::shared_ptr< RNodeBase > UpcastNode(std::shared_ptr< RNodeBase > ptr)
std::vector< std::string > GetFilterNames(const std::shared_ptr< RLoopManager > &loopManager)
ColumnNames_t ConvertRegexToColumns(const RDFInternal::RBookedCustomColumns &customColumns, TTree *tree, ROOT::RDF::RDataSource *dataSource, std::string_view columnNameRegexp, std::string_view callerName)
std::string PrettyPrintAddr(const void *const addr)
std::shared_ptr< RJittedCustomColumn > BookDefineJit(std::string_view name, std::string_view expression, RLoopManager &lm, RDataSource *ds, const RDFInternal::RBookedCustomColumns &customCols, const ColumnNames_t &branches, std::shared_ptr< RNodeBase > *upcastNodeOnHeap)
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)
ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, const ColumnNames_t &datasetColumns, const ColumnNames_t &definedCols, const ColumnNames_t &dataSourceColumns)
HeadNode_t CreateSnapshotRDF(const ColumnNames_t &validCols, std::string_view treeName, std::string_view fileName, bool isLazy, RLoopManager &loopManager, std::unique_ptr< RDFInternal::RActionBase > actionPtr)
std::string JitBuildAction(const ColumnNames_t &bl, std::shared_ptr< RDFDetail::RNodeBase > *prevNode, const std::type_info &art, const std::type_info &at, void *rOnHeap, TTree *tree, const unsigned int nSlots, const RDFInternal::RBookedCustomColumns &customCols, RDataSource *ds, std::weak_ptr< RJittedAction > *jittedActionOnHeap)
bool IsInternalColumn(std::string_view colName)
ColumnNames_t GetValidatedColumnNames(RLoopManager &lm, const unsigned int nColumns, const ColumnNames_t &columns, const ColumnNames_t &validCustomColumns, RDataSource *ds)
Given the desired number of columns and the user-provided list of columns:
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 CheckCustomColumn(std::string_view definedCol, TTree *treePtr, const ColumnNames_t &customCols, const std::map< std::string, std::string > &aliasMap, const ColumnNames_t &dataSourceColumns)
double T(double x)
Definition: ChebyshevPol.h:34
void function(const Char_t *name_, T fun, const Char_t *docstring=0)
Definition: RExports.h:151
ROOT type_traits extensions.
Definition: TypeTraits.hxx:21
T Sum(const RVec< T > &v)
Sum elements of an RVec.
Definition: RVec.hxx:759
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:939
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Definition: StringConv.hxx:21
RooArgSet S(const RooAbsArg &v1)
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:212
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:1063
Short_t Min(Short_t a, Short_t b)
Definition: TMathBase.h:180
Double_t StdDev(Long64_t n, const T *a, const Double_t *w=0)
Definition: TMath.h:518
Definition: tree.py:1
Lightweight storage for a collection of types.
Definition: TypeTraits.hxx:25
auto * a
Definition: textangle.C:12