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>>
139 auto MapReduce(F func, ROOT::TSeq<INTEGER> args, R redfunc) -> InvokeResult_t<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
Error("WriteTObject","The current directory (%s) is not associated with a file. The object (%s) has not been written.", GetName(), objname)
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 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 MapImpl(F func, unsigned nTimes) -> std::vector< InvokeResult_t< F > >=delete
Implementation of the Map method, left to the derived classes.
TExecutorCRTP()=default
TExecutorCRTP(const TExecutorCRTP &)=delete
auto Map(F func, unsigned nTimes) -> std::vector< InvokeResult_t< F > >
Execute a function without arguments several times.
T * Reduce(const std::vector< T * > &mergeObjs)
"Reduce" an std::vector into a single object by using the object's Merge method.
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)
namespace associated R package for ROOT.
Definition RExports.h:72
Long64_t(* MergeFunc_t)(void *, TCollection *, TFileMergeInfo *)
Definition Rtypes.h:121
TLine l
Definition textangle.C:4