Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TExecutorCRTP.hxx
Go to the documentation of this file.
1// @(#)root/core/base:$Id$
2// Author: Xavier Valls November 2020
3
4/*************************************************************************
5 * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#ifndef ROOT_TExecutorCRTP
13#define ROOT_TExecutorCRTP
14
15#include "ROOT/TSeq.hxx"
16#include "ROOT/TypeTraits.hxx" // InvokeResult_t
17#include "TError.h"
18#include "TList.h"
19
20#include <initializer_list>
21#include <type_traits> //std::enable_if
22#include <utility> //std::move
23#include <vector>
24
25//////////////////////////////////////////////////////////////////////////
26///
27/// \class ROOT::TExecutorCRTP
28/// \brief This class defines an interface to execute the same task
29/// multiple times, possibly in parallel and with different arguments every
30/// time.
31///
32/// ###ROOT::TExecutorCRTP<SubC>::Map
33/// The two possible usages of the Map method are:\n
34/// * `Map(F func, unsigned nTimes)`: func is executed nTimes with no arguments
35/// * `Map(F func, T& args)`: func is executed on each element of the collection of arguments args
36///
37/// The Map function forwards the call to MapImpl, to be implemented by the child classes.
38///
39/// For either signature, func is executed as many times as needed by a pool of
40/// n workers, where n typically defaults to the number of available cores.\n
41/// A collection containing the result of each execution is returned.\n
42/// **Note:** the user is responsible for the deletion of any object that might
43/// be created upon execution of func, returned objects included. ROOT::TExecutorCRTP derived classes
44/// never delete what they return, they simply forget it.\n
45///
46/// \param func
47/// \parblock
48/// a callable object, such as a lambda expression, an std::function, a
49/// functor object or a function that takes zero arguments (for the first signature)
50/// or one (for the second signature).
51/// \endparblock
52/// \param args
53/// \parblock
54/// a standard vector, a ROOT::TSeq of integer type or an initializer list for the second signature.
55/// An integer only for the first.\n
56/// \endparblock
57///
58/// **Note:** in cases where the function to be executed takes more than
59/// zero/one argument but all are fixed except zero/one, the function can be wrapped
60/// in a lambda or via std::bind to give it the right signature.\n
61///
62/// #### Return value:
63/// An std::vector. The elements in the container
64/// will be the objects returned by func. The ordering of the elements corresponds to the ordering of
65/// the arguments.
66///
67/// ### ROOT::TExecutorCRTP<SubC>::Reduce
68/// These set of methods combine all elements from a std::vector into a single value.
69/// \param redfunc
70/// \parblock
71/// a callable object, such as a lambda expression, an std::function, a
72/// functor object or a function that takes an std::vector and combines all its elements into a single result.\n
73/// \endparblock
74/// \param [args]
75/// \parblock
76/// a standard vector\n
77/// \endparblock
78///
79/// ### ROOT::TExecutorCRTP<SubC>::MapReduce
80/// This set of methods behaves exactly like Map, but takes an additional
81/// function as a third argument. This function is applied to the set of
82/// objects returned by the corresponding Map execution to "squash" them
83/// into a single object. This function should be independent of the size of
84/// the vector returned by Map due to optimization of the number of chunks.
85///
86/// #### Examples:
87/// ~~~{.cpp}
88/// Generate 1 ten times and sum those tens
89/// root[] ROOT::TProcessExecutor pool; auto ten = pool.MapReduce([]() { return 1; }, 10, [](const std::vector<int> &v) { return std::accumulate(v.begin(), v.end(), 0); })
90/// root[] ROOT::TProcessExecutor pool; auto tenOnes = pool.Map([]() { return 1; }, 10); auto ten = Reduce([](const std::vector<int> &v) { return std::accumulate(v.begin(), v.end(), 0); }, tenOnes)
91///
92/// Create 10 histograms and merge them into one
93/// root[] ROOT::TThreadExecutor pool; auto hist = pool.MapReduce(CreateAndFillHists, 10, PoolUtils::ReduceObjects);
94///
95/// ~~~
96///
97//////////////////////////////////////////////////////////////////////////
98
99
100namespace ROOT {
101
102template<class SubC>
104
105protected:
106 template <typename F, typename... Args>
107 using InvokeResult_t = ROOT::TypeTraits::InvokeResult_t<F, Args...>;
108
109 /// type definition used in templated functions for not allowing mapping functions that return references or void.
110 /// The resulting vector elements must be assignable, references aren't.
111 template <class F, class... T>
113 std::enable_if_t<!std::is_reference<InvokeResult_t<F, T...>>::value && !std::is_void<InvokeResult_t<F, T...>>::value>;
114
115public:
116 TExecutorCRTP() = default;
117 TExecutorCRTP(const TExecutorCRTP &) = delete;
119
120 // Map
121 // These trailing return types allow for a compile time check of compatibility between function signatures and args
122 template <class F, class Cond = validMapReturnCond<F>>
123 auto Map(F func, unsigned nTimes) -> std::vector<InvokeResult_t<F>>;
124 template <class F, class INTEGER, class Cond = validMapReturnCond<F, INTEGER>>
125 auto Map(F func, ROOT::TSeq<INTEGER> args) -> std::vector<InvokeResult_t<F, INTEGER>>;
126 template <class F, class T, class Cond = validMapReturnCond<F, T>>
127 auto Map(F func, std::initializer_list<T> args) -> std::vector<InvokeResult_t<F, T>>;
128 template <class F, class T, class Cond = validMapReturnCond<F, T>>
129 auto Map(F func, std::vector<T> &args) -> std::vector<InvokeResult_t<F, T>>;
130 template <class F, class T, class Cond = validMapReturnCond<F, T>>
131 auto Map(F func, const std::vector<T> &args) -> std::vector<InvokeResult_t<F, T>>;
132
133 // MapReduce
134 // The trailing return types check at compile time that func is compatible with the type of the arguments.
135 // A static_assert check in TExecutorCRTP<SubC>::Reduce is used to check that redfunc is compatible with the type returned by func
136 template <class F, class R, class Cond = validMapReturnCond<F>>
137 auto MapReduce(F func, unsigned nTimes, R redfunc) -> InvokeResult_t<F>;
138 template <class F, class INTEGER, class R, class Cond = validMapReturnCond<F, INTEGER>>
140 template <class F, class T, class R, class Cond = validMapReturnCond<F, T>>
141 auto MapReduce(F func, std::initializer_list<T> args, R redfunc) -> InvokeResult_t<F, T>;
142 template <class F, class T, class R, class Cond = validMapReturnCond<F, T>>
143 auto MapReduce(F func, const std::vector<T> &args, R redfunc) -> InvokeResult_t<F, T>;
144 template <class F, class T, class R, class Cond = validMapReturnCond<F, T>>
145 auto MapReduce(F func, std::vector<T> &args, R redfunc) -> InvokeResult_t<F, T>;
146 template<class F, class T,class Cond = validMapReturnCond<F, T>>
147 T* MapReduce(F func, std::vector<T*> &args);
148 template<class F, class T,class Cond = validMapReturnCond<F, T>>
149 T* MapReduce(F func, const std::vector<T*> &args);
150
151 template<class T> T* Reduce(const std::vector<T*> &mergeObjs);
152 template<class T, class R> auto Reduce(const std::vector<T> &objs, R redfunc) -> decltype(redfunc(objs));
153
154private:
155
156 SubC &Derived()
157 {
158 return *static_cast<SubC*>(this);
159 }
160
161 /// Implementation of the Map method, left to the derived classes
162 template <class F, class Cond = validMapReturnCond<F>>
163 auto MapImpl(F func, unsigned nTimes) -> std::vector<InvokeResult_t<F>> = delete;
164 /// Implementation of the Map method, left to the derived classes
165 template <class F, class INTEGER, class Cond = validMapReturnCond<F, INTEGER>>
166 auto MapImpl(F func, ROOT::TSeq<INTEGER> args) -> std::vector<InvokeResult_t<F, INTEGER>> = delete;
167 /// Implementation of the Map method, left to the derived classes
168 template <class F, class T, class Cond = validMapReturnCond<F, T>>
169 auto MapImpl(F func, std::vector<T> &args) -> std::vector<InvokeResult_t<F, T>> = delete;
170 /// Implementation of the Map method, left to the derived classes
171 template <class F, class T, class Cond = validMapReturnCond<F, T>>
172 auto MapImpl(F func, const std::vector<T> &args) -> std::vector<InvokeResult_t<F, T>> = delete;
173};
174
175//////////////////////////////////////////////////////////////////////////
176/// \brief Execute a function without arguments several times.
177///
178/// \param func Function to be executed.
179/// \param nTimes Number of times function should be called.
180/// \return A vector with the results of the function calls.
181/// Functions that take arguments can be executed (with
182/// fixed arguments) by wrapping them in a lambda or with std::bind.
183template <class SubC>
184template <class F, class Cond>
185auto TExecutorCRTP<SubC>::Map(F func, unsigned nTimes) -> std::vector<InvokeResult_t<F>>
186{
187 return Derived().MapImpl(func, nTimes);
188}
189
190//////////////////////////////////////////////////////////////////////////
191/// \brief Execute a function over a sequence of indexes.
192///
193/// \param func Function to be executed. Must take an element of the sequence passed assecond argument as a parameter.
194/// \param args Sequence of indexes to execute `func` on.
195/// \return A vector with the results of the function calls.
196template <class SubC>
197template <class F, class INTEGER, class Cond>
198auto TExecutorCRTP<SubC>::Map(F func, ROOT::TSeq<INTEGER> args) -> std::vector<InvokeResult_t<F, INTEGER>>
199{
200 return Derived().MapImpl(func, args);
201}
202
203//////////////////////////////////////////////////////////////////////////
204/// \brief Execute a function over the elements of an initializer_list.
205///
206/// \param func Function to be executed on the elements of the initializer_list passed as second parameter.
207/// \param args initializer_list for a vector to apply `func` on.
208/// \return A vector with the results of the function calls.
209template <class SubC>
210template <class F, class T, class Cond>
211auto TExecutorCRTP<SubC>::Map(F func, std::initializer_list<T> args) -> std::vector<InvokeResult_t<F, T>>
212{
213 std::vector<T> vargs(std::move(args));
214 const auto &reslist = Map(func, vargs);
215 return reslist;
216}
217
218//////////////////////////////////////////////////////////////////////////
219/// \brief Execute a function over the elements of a vector.
220///
221/// \param func Function to be executed on the elements of the vector passed as second parameter.
222/// \param args Vector of elements passed as an argument to `func`.
223/// \return A vector with the results of the function calls.
224template <class SubC>
225template <class F, class T, class Cond>
226auto TExecutorCRTP<SubC>::Map(F func, std::vector<T> &args) -> std::vector<InvokeResult_t<F, T>>
227{
228 return Derived().MapImpl(func, args);
229}
230
231//////////////////////////////////////////////////////////////////////////
232/// \brief Execute a function over the elements of an immutable vector
233
234///
235/// \param func Function to be executed on the elements of the vector passed as second parameter.
236/// \param args Vector of elements passed as an argument to `func`.
237/// \return A vector with the results of the function calls.
238template <class SubC>
239template <class F, class T, class Cond>
240auto TExecutorCRTP<SubC>::Map(F func, const std::vector<T> &args) -> std::vector<InvokeResult_t<F, T>>
241{
242 return Derived().MapImpl(func, args);
243}
244
245//////////////////////////////////////////////////////////////////////////
246/// \brief Execute a function without arguments several times (Map) and accumulate the results into a single value (Reduce).
247///
248/// \param func Function to be executed.
249/// \param nTimes Number of times function should be called.
250/// \return A vector with the results of the function calls.
251/// \param redfunc Reduction function to combine the results of the calls to `func`. Must return the same type as `func`.
252/// \return A value result of "reducing" the vector returned by the Map operation into a single object.
253template <class SubC>
254template <class F, class R, class Cond>
255auto TExecutorCRTP<SubC>::MapReduce(F func, unsigned nTimes, R redfunc) -> InvokeResult_t<F>
256{
257 return Reduce(Map(func, nTimes), redfunc);
258}
259
260//////////////////////////////////////////////////////////////////////////
261/// \brief Execute a function over a sequence of indexes (Map) and accumulate the results into a single value (Reduce).
262///
263/// \param func Function to be executed. Must take an element of the sequence passed assecond argument as a parameter.
264/// \param args Sequence of indexes to execute `func` on.
265/// \param redfunc Reduction function to combine the results of the calls to `func`. Must return the same type as `func`.
266/// \return A value result of "reducing" the vector returned by the Map operation into a single object.
267template <class SubC>
268template <class F, class INTEGER, class R, class Cond>
270{
271 return Reduce(Map(func, args), redfunc);
272}
273
274//////////////////////////////////////////////////////////////////////////
275/// \brief Execute a function over the elements of an initializer_list (Map) and accumulate the results into a single value (Reduce).
276///
277/// \param func Function to be executed on the elements of the initializer_list passed as second parameter.
278/// \param args initializer_list for a vector to apply `func` on.
279/// \param redfunc Reduction function to combine the results of the calls to `func`. Must return the same type as `func`.
280/// \return A value result of "reducing" the vector returned by the Map operation into a single object.
281template <class SubC>
282template <class F, class T, class R, class Cond>
283auto TExecutorCRTP<SubC>::MapReduce(F func, std::initializer_list<T> args, R redfunc) -> InvokeResult_t<F, T>
284{
285 std::vector<T> vargs(std::move(args));
286 return Reduce(Map(func, vargs), redfunc);
287}
288
289//////////////////////////////////////////////////////////////////////////
290/// \brief Execute a function over the elements of a vector (Map) and accumulate the results into a single value (Reduce).
291///
292/// \param func Function to be executed on the elements of the vector passed as second parameter.
293/// \param args Vector of elements passed as an argument to `func`.
294/// \param redfunc Reduction function to combine the results of the calls to `func`. Must return the same type as `func`.
295/// \return A value result of "reducing" the vector returned by the Map operation into a single object.
296template <class SubC>
297template <class F, class T, class R, class Cond>
298auto TExecutorCRTP<SubC>::MapReduce(F func, std::vector<T> &args, R redfunc) -> InvokeResult_t<F, T>
299{
300 return Reduce(Map(func, args), redfunc);
301}
302
303//////////////////////////////////////////////////////////////////////////
304/// \brief Execute a function over the elements of an immutable vector (Map) and accumulate the results into a single value (Reduce).
305///
306/// \param func Function to be executed on the elements of the vector passed as second parameter.
307/// \param args Immutable vector of elements passed as an argument to `func`.
308/// \param redfunc Reduction function to combine the results of the calls to `func`. Must return the same type as `func`.
309/// \return A value result of "reducing" the vector returned by the Map operation into a single object.
310template <class SubC>
311template <class F, class T, class R, class Cond>
312auto TExecutorCRTP<SubC>::MapReduce(F func, const std::vector<T> &args, R redfunc) -> InvokeResult_t<F, T>
313{
314 return Reduce(Map(func, args), redfunc);
315}
316
317//////////////////////////////////////////////////////////////////////////
318/// \brief Execute a function over the TObject-inheriting elements of a vector (Map) and merge the objects into a single one (Reduce).
319///
320/// \param func Function to be executed on the elements of the vector passed as second parameter.
321/// \param args Vector of elements passed as an argument to `func`.
322/// \return A value result of "reducing" the vector returned by the Map operation into a single object.
323template<class SubC> template<class F, class T, class Cond>
324T* TExecutorCRTP<SubC>::MapReduce(F func, std::vector<T*> &args)
325{
326 return Reduce(Map(func, args));
327}
328
329//////////////////////////////////////////////////////////////////////////
330/// \brief Execute a function over the TObject-inheriting elements of an immutable vector (Map) and merge the objects into a single one (Reduce).
331///
332/// \param func Function to be executed on the elements of the vector passed as second parameter.
333/// \param args Immutable vector of elements passed as an argument to `func`.
334/// \return A value result of "reducing" the vector returned by the Map operation into a single object.
335template<class SubC> template<class F, class T, class Cond>
336T* TExecutorCRTP<SubC>::MapReduce(F func, const std::vector<T*> &args)
337{
338 return Reduce(Map(func, args));
339}
340
341//////////////////////////////////////////////////////////////////////////
342/// \brief "Reduce" an std::vector into a single object by using the object's Merge method.
343///
344/// \param mergeObjs A vector of ROOT objects implementing the Merge method
345/// \return An object result of merging the vector elements into one.
346template<class SubC> template<class T>
347T* TExecutorCRTP<SubC>::Reduce(const std::vector<T*> &mergeObjs)
348{
349 ROOT::MergeFunc_t merge = mergeObjs.front()->IsA()->GetMerge();
350 if(!merge) {
351 Error("TExecutorCRTP<SubC>::Reduce", "could not find merge method for the TObject\n. Aborting operation.");
352 return nullptr;
353 }
354
355 TList l;
356 for(unsigned i =1; i<mergeObjs.size(); i++){
357 l.Add(mergeObjs[i]);
358 }
359 // use clone to return a new object
360 auto retHist = dynamic_cast<T*>((mergeObjs.front())->Clone());
361 if (retHist) retHist->Merge(&l);
362 return retHist;
363}
364
365//////////////////////////////////////////////////////////////////////////
366/// \brief "Reduce" an std::vector into a single object by passing a
367/// function as the second argument defining the reduction operation.
368///
369/// \param objs A vector of elements to combine.
370/// \param redfunc Reduction function to combine the elements of the vector `objs`
371/// \return A value result of combining the vector elements into a single object of the same type.
372template<class SubC> template<class T, class R>
373auto TExecutorCRTP<SubC>::Reduce(const std::vector<T> &objs, R redfunc) -> decltype(redfunc(objs))
374{
375 // check we can apply reduce to objs
376 static_assert(std::is_same<decltype(redfunc(objs)), T>::value, "redfunc does not have the correct signature");
377 return redfunc(objs);
378}
379
380} // end namespace ROOT
381#endif
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:185
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
This class defines an interface to execute the same task multiple times, possibly in parallel and wit...
auto MapImpl(F func, std::vector< T > &args) -> std::vector< InvokeResult_t< F, T > >=delete
Implementation of the Map method, left to the derived classes.
ROOT::TypeTraits::InvokeResult_t< F, Args... > InvokeResult_t
auto MapReduce(F func, unsigned nTimes, R redfunc) -> InvokeResult_t< F >
Execute a function without arguments several times (Map) and accumulate the results into a single val...
auto MapReduce(F func, ROOT::TSeq< INTEGER > args, R redfunc) -> InvokeResult_t< F, INTEGER >
Execute a function over a sequence of indexes (Map) and accumulate the results into a single value (R...
auto MapReduce(F func, const std::vector< T > &args, R redfunc) -> InvokeResult_t< F, T >
Execute a function over the elements of an immutable vector (Map) and accumulate the results into a s...
auto Map(F func, std::initializer_list< T > args) -> std::vector< InvokeResult_t< F, T > >
Execute a function over the elements of an initializer_list.
T * MapReduce(F func, const std::vector< T * > &args)
Execute a function over the TObject-inheriting elements of an immutable vector (Map) and merge the ob...
auto MapImpl(F func, unsigned nTimes) -> std::vector< InvokeResult_t< F > >=delete
Implementation of the Map method, left to the derived classes.
auto Map(F func, std::vector< T > &args) -> std::vector< InvokeResult_t< F, T > >
Execute a function over the elements of a vector.
TExecutorCRTP()=default
auto Map(F func, const std::vector< T > &args) -> std::vector< InvokeResult_t< F, T > >
Execute a function over the elements of an immutable vector.
TExecutorCRTP(const TExecutorCRTP &)=delete
auto Map(F func, ROOT::TSeq< INTEGER > args) -> std::vector< InvokeResult_t< F, INTEGER > >
Execute a function over a sequence of indexes.
auto Map(F func, unsigned nTimes) -> std::vector< InvokeResult_t< F > >
Execute a function without arguments several times.
std::enable_if_t<!std::is_reference< InvokeResult_t< F, T... > >::value &&!std::is_void< InvokeResult_t< F, T... > >::value > validMapReturnCond
type definition used in templated functions for not allowing mapping functions that return references...
auto MapReduce(F func, std::vector< T > &args, R redfunc) -> InvokeResult_t< F, T >
Execute a function over the elements of a vector (Map) and accumulate the results into a single value...
T * Reduce(const std::vector< T * > &mergeObjs)
"Reduce" an std::vector into a single object by using the object's Merge method.
T * MapReduce(F func, std::vector< T * > &args)
Execute a function over the TObject-inheriting elements of a vector (Map) and merge the objects into ...
auto MapReduce(F func, std::initializer_list< T > args, R redfunc) -> InvokeResult_t< F, T >
Execute a function over the elements of an initializer_list (Map) and accumulate the results into a s...
auto Reduce(const std::vector< T > &objs, R redfunc) -> decltype(redfunc(objs))
"Reduce" an std::vector into a single object by passing a function as the second argument defining th...
TExecutorCRTP & operator=(const TExecutorCRTP &)=delete
auto MapImpl(F func, const std::vector< T > &args) -> std::vector< InvokeResult_t< F, T > >=delete
Implementation of the Map method, left to the derived classes.
auto MapImpl(F func, ROOT::TSeq< INTEGER > args) -> std::vector< InvokeResult_t< F, INTEGER > >=delete
Implementation of the Map method, left to the derived classes.
A pseudo container class which is a generator of indices.
Definition TSeq.hxx:67
A doubly linked list.
Definition TList.h:38
#define F(x, y, z)
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Long64_t(* MergeFunc_t)(void *, TCollection *, TFileMergeInfo *)
Definition Rtypes.h:115
TLine l
Definition textangle.C:4