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