Logo ROOT   master
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 
41 class TObjArray;
42 class TTree;
43 namespace ROOT {
44 namespace Detail {
45 namespace RDF {
46 class RNodeBase;
47 }
48 }
49 namespace RDF {
50 template <typename T>
51 class RResultPtr;
52 template<typename T, typename V>
53 class RInterface;
55 class RDataSource;
56 } // namespace RDF
57 
58 } // namespace ROOT
59 
60 /// \cond HIDDEN_SYMBOLS
61 
62 namespace ROOT {
63 namespace Internal {
64 namespace RDF {
65 using namespace ROOT::Detail::RDF;
66 using namespace ROOT::RDF;
67 namespace TTraits = ROOT::TypeTraits;
69 
71 HeadNode_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 
78 std::string DemangleTypeIdName(const std::type_info &typeInfo);
79 
80 ColumnNames_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.
85 class RIgnoreErrorLevelRAII {
86 private:
87  int fCurIgnoreErrorLevel = gErrorIgnoreLevel;
88 
89 public:
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.
98 namespace ActionTags {
99 struct Histo1D{};
100 struct Histo2D{};
101 struct Histo3D{};
102 struct Graph{};
103 struct Profile1D{};
104 struct Profile2D{};
105 struct Min{};
106 struct Max{};
107 struct Sum{};
108 struct Mean{};
109 struct Fill{};
110 struct StdDev{};
111 struct Display{};
112 }
113 // clang-format on
114 
115 template <typename T, bool ISV6HISTO = std::is_base_of<TH1, T>::value>
116 struct 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 
125 template <typename T>
126 struct 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)
132 template <typename... BranchTypes, typename ActionTag, typename ActionResultType, typename PrevNodeType>
133 std::unique_ptr<RActionBase>
134 BuildAction(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
143 template <typename... BranchTypes, typename PrevNodeType>
144 std::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 
161 template <typename... BranchTypes, typename PrevNodeType>
162 std::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
172 template <typename BranchType, typename PrevNodeType, typename ActionResultType>
173 std::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
183 template <typename BranchType, typename PrevNodeType, typename ActionResultType>
184 std::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
194 template <typename BranchType, typename PrevNodeType, typename ActionResultType>
195 std::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
205 template <typename BranchType, typename PrevNodeType>
206 std::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
216 template <typename BranchType, typename PrevNodeType>
217 std::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
227 template <typename... BranchTypes, typename PrevNodeType>
228 std::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 
239 template <typename Filter>
240 void 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 
247 void 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 
250 std::string PrettyPrintAddr(const void *const addr);
251 
252 void BookFilterJit(const std::shared_ptr<RJittedFilter> &jittedFilter, std::shared_ptr<RNodeBase> *prevNodeOnHeap,
253  std::string_view name, std::string_view expression,
254  const std::map<std::string, std::string> &aliasMap, const ColumnNames_t &branches,
255  const RDFInternal::RBookedCustomColumns &customCols, TTree *tree, RDataSource *ds);
256 
257 std::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 
262 std::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.
273 template <typename T>
274 std::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.
280 template <typename T>
281 std::shared_ptr<T> *MakeSharedOnHeap(const std::shared_ptr<T> &shPtr)
282 {
283  return new std::shared_ptr<T>(shPtr);
284 }
285 
286 bool 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.
290 std::shared_ptr<RNodeBase> UpcastNode(std::shared_ptr<RNodeBase> ptr);
291 
292 ColumnNames_t GetValidatedColumnNames(RLoopManager &lm, const unsigned int nColumns, const ColumnNames_t &columns,
293  const ColumnNames_t &validCustomColumns, RDataSource *ds);
294 
295 std::vector<std::string> GetValidatedArgTypes(const ColumnNames_t &colNames, const RBookedCustomColumns &customColumns,
296  TTree *tree, RDataSource *ds, const std::string &context,
297  bool vector2rvec);
298 
299 std::vector<bool> FindUndefinedDSColumns(const ColumnNames_t &requestedCols, const ColumnNames_t &definedDSCols);
300 
301 using ROOT::Detail::RDF::ColumnNames_t;
302 
303 template <typename T>
304 void 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]; };
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)
318 template <typename... ColumnTypes, std::size_t... S>
320 AddDSColumns(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
343 template <typename F, typename PrevNode>
344 void JitFilterHelper(F &&f, const ColumnNames_t &cols, std::string_view name,
345  std::weak_ptr<RJittedFilter> *wkJittedFilter, std::shared_ptr<PrevNode> *prevNodeOnHeap,
346  RDFInternal::RBookedCustomColumns *customColumns)
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;
363  using F_t = RFilter<Callable_t, PrevNode>;
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 
384 template <typename F>
385 void 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
430 template <typename ActionTag, typename... BranchTypes, typename PrevNodeType, typename ActionResultType>
431 void 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,
433  RDFInternal::RBookedCustomColumns *customColumns)
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.
472 template <typename T, bool Container = RDFInternal::IsDataContainer<T>::value && !std::is_same<T, std::string>::value>
473 struct TMinReturnType {
474  using type = T;
475 };
476 
477 template <>
478 struct TMinReturnType<RInferredType, false> {
479  using type = double;
480 };
481 
482 template <typename T>
483 struct TMinReturnType<T, true> {
485 };
486 
487 // return wrapper around f that prepends an `unsigned int slot` parameter
488 template <typename R, typename F, typename... Args>
489 std::function<R(unsigned int, Args...)> AddSlotParameter(F &f, TypeList<Args...>)
490 {
491  return [f](unsigned int, Args... a) -> R { return f(a...); };
492 }
493 
494 template <typename BranchType, typename... Rest>
495 struct TNeedJitting {
496  static constexpr bool value = TNeedJitting<Rest...>::value;
497 };
498 
499 template <typename... Rest>
500 struct TNeedJitting<RInferredType, Rest...> {
501  static constexpr bool value = true;
502 };
503 
504 template <typename T>
505 struct TNeedJitting<T> {
506  static constexpr bool value = false;
507 };
508 
509 template <>
510 struct 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>
522 void 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
536 template <typename R, typename T>
537 void 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.
544 void CheckTypesAndPars(unsigned int nTemplateParams, unsigned int nColumnNames);
545 
546 /// Return local BranchNames or default BranchNames according to which one should be used
547 const 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.
550 ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, const ColumnNames_t &datasetColumns,
551  const ColumnNames_t &definedCols, const ColumnNames_t &dataSourceColumns);
552 
553 bool IsInternalColumn(std::string_view colName);
554 
555 /// Returns the list of Filters defined in the whole graph
556 std::vector<std::string> GetFilterNames(const std::shared_ptr<RLoopManager> &loopManager);
557 
558 /// Returns the list of Filters defined in the branch
559 template <typename NodeType>
560 std::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
568 template <bool...>
569 struct TBoolPack;
570 
571 template <bool... bs>
572 using IsTrueForAllImpl_t = typename std::is_same<TBoolPack<bs..., true>, TBoolPack<true, bs...>>;
573 
574 template <bool... Conditions>
575 struct 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 
582 template <typename>
583 struct IsList_t : std::false_type {};
584 
585 template <typename T>
586 struct IsList_t<std::list<T>> : std::true_type {};
587 
588 template <typename>
589 struct IsDeque_t : std::false_type {};
590 
591 template <typename T>
592 struct IsDeque_t<std::deque<T>> : std::true_type {};
593 // clang-format on
594 
595 } // namespace RDF
596 } // namespace Internal
597 
598 namespace Detail {
599 namespace RDF {
600 
601 /// The aliased type is `double` if `T == RInferredType`, `U` if `T == container<U>`, `T` otherwise.
602 template <typename T>
603 using MinReturnType_t = typename RDFInternal::TMinReturnType<T>::type;
604 
605 template <typename T>
606 using MaxReturnType_t = MinReturnType_t<T>;
607 
608 template <typename T>
609 using SumReturnType_t = MinReturnType_t<T>;
610 
611 } // namespace RDF
612 } // namespace Detail
613 } // namespace ROOT
614 
615 /// \endcond
616 
617 #endif
Smart pointer for the return type of actions.
An array of TObjects.
Definition: TObjArray.h:37
double
Definition: Converters.cxx:921
The head node of a RDF computation graph.
bool AtLeastOneEmptyString(const std::vector< std::string_view > strings)
R__EXTERN Int_t gErrorIgnoreLevel
Definition: TError.h:105
Returns the available number of logical cores.
Definition: RNumpyDS.hxx:30
bool IsInternalColumn(std::string_view colName)
typename TakeFirstParameter< T >::type TakeFirstParameter_t
Definition: TypeTraits.hxx:155
double T(double x)
Definition: ChebyshevPol.h:34
#define g(i)
Definition: RSha256.hxx:105
#define f(i)
Definition: RSha256.hxx:104
Short_t Min(Short_t a, Short_t b)
Definition: TMathBase.h:180
STL namespace.
#define R(a, b, c, d, e, f, g, h, i)
Definition: RSha256.hxx:110
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)
virtual std::string GetTypeName(std::string_view) const =0
Type of a column as a string, e.g.
std::shared_ptr< RNodeBase > UpcastNode(std::shared_ptr< RNodeBase > ptr)
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.
unsigned int GetNSlots() const
void function(const Char_t *name_, T fun, const Char_t *docstring=0)
Definition: RExports.h:151
std::vector< std::string > GetFilterNames(const std::shared_ptr< RLoopManager > &loopManager)
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:938
ColumnNames_t FindUnknownColumns(const ColumnNames_t &requiredCols, const ColumnNames_t &datasetColumns, const ColumnNames_t &definedCols, const ColumnNames_t &dataSourceColumns)
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::string DemangleTypeIdName(const std::type_info &typeInfo)
RooArgSet S(const RooAbsArg &v1)
#define F(x, y, z)
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)
auto * a
Definition: textangle.C:12
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 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
The public interface to the RDataFrame federation of classes.
std::vector< std::string > GetValidatedArgTypes(const ColumnNames_t &colNames, const RBookedCustomColumns &customColumns, TTree *tree, RDataSource *ds, const std::string &context, bool vector2rvec)
#define h(i)
Definition: RSha256.hxx:106
Lightweight storage for a collection of types.
Definition: TypeTraits.hxx:25
Double_t StdDev(Long64_t n, const T *a, const Double_t *w=0)
Definition: TMath.h:518
#define d(i)
Definition: RSha256.hxx:102
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:
int type
Definition: TGX11.cxx:120
ROOT type_traits extensions.
Definition: TypeTraits.hxx:21
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)
Extract types from the signature of a callable object. See CallableTraits.
Definition: TypeTraits.hxx:36
T Sum(const RVec< T > &v)
Sum elements of an RVec.
Definition: RVec.hxx:758
typedef void((*Func_t)())
RDataSource * GetDataSource() const
std::string PrettyPrintAddr(const void *const addr)
void CheckTypesAndPars(unsigned int nTemplateParams, unsigned int nColumnNames)
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:212
you should not use this method at all Int_t Int_t Double_t Double_t Double_t Int_t Double_t Double_t Double_t Double_t b
Definition: TRolke.cxx:630
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)
std::vector< T ** > GetColumnReaders(std::string_view columnName)
Called at most once per column by RDF.
Definition: tree.py:1
Encapsulates the columns defined by the user.
A TTree represents a columnar dataset.
Definition: TTree.h:78
RDataSource defines an API that RDataFrame can use to read arbitrary data formats.
ColumnNames_t GetNames() const
Returns the list of the names of the defined columns.
char name[80]
Definition: TGX11.cxx:109
ColumnNames_t ConvertRegexToColumns(const RDFInternal::RBookedCustomColumns &customColumns, TTree *tree, ROOT::RDF::RDataSource *dataSource, std::string_view columnNameRegexp, std::string_view callerName)