Logo ROOT  
Reference Guide
TExecutor.hxx
Go to the documentation of this file.
1// @(#)root/thread:$Id$
2// Author: Xavier Valls March 2016
3
4/*************************************************************************
5 * Copyright (C) 1995-2006, 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_TExecutor
13#define ROOT_TExecutor
14
15#include "ROOT/TSeq.hxx"
16#include "TList.h"
17#include <vector>
18
19//////////////////////////////////////////////////////////////////////////
20///
21/// \class ROOT::TExecutor
22/// \brief This class defines an interface to execute the same task
23/// multiple times in parallel, possibly with different arguments every
24/// time. The classes implementing it mimic the behaviour of python's pool.Map method.
25///
26/// ###ROOT::TExecutor::Map
27/// The two possible usages of the Map method are:\n
28/// * Map(F func, unsigned nTimes): func is executed nTimes with no arguments
29/// * Map(F func, T& args): func is executed on each element of the collection of arguments args
30///
31/// For either signature, func is executed as many times as needed by a pool of
32/// nThreads threads; It defaults to the number of cores.\n
33/// A collection containing the result of each execution is returned.\n
34/// **Note:** the user is responsible for the deletion of any object that might
35/// be created upon execution of func, returned objects included: ROOT::TExecutor never
36/// deletes what it returns, it simply forgets it.\n
37///
38/// \param func
39/// \parblock
40/// a lambda expression, an std::function, a loaded macro, a
41/// functor class or a function that takes zero arguments (for the first signature)
42/// or one (for the second signature).
43/// \endparblock
44/// \param args
45/// \parblock
46/// a standard vector, a ROOT::TSeq of integer type or an initializer list for the second signature.
47/// An integer only for the first.\n
48/// \endparblock
49///
50/// **Note:** in cases where the function to be executed takes more than
51/// zero/one argument but all are fixed except zero/one, the function can be wrapped
52/// in a lambda or via std::bind to give it the right signature.\n
53///
54/// #### Return value:
55/// An std::vector. The elements in the container
56/// will be the objects returned by func.
57
58namespace ROOT {
59
60template<class subc>
61class TExecutor {
62public:
63 explicit TExecutor() = default;
64 explicit TExecutor(size_t /* nThreads */ ){};
65
66 template< class F, class... T>
67 using noReferenceCond = typename std::enable_if<"Function can't return a reference" && !(std::is_reference<typename std::result_of<F(T...)>::type>::value)>::type;
68
69 // // Map
70 // //these late return types allow for a compile-time check of compatibility between function signatures and args,
71 // //and a compile-time check that the argument list implements a front() method (all STL sequence containers have it)
72 template<class F, class Cond = noReferenceCond<F>>
73 auto Map(F func, unsigned nTimes) -> std::vector<typename std::result_of<F()>::type>;
74 template<class F, class INTEGER, class Cond = noReferenceCond<F, INTEGER>>
75 auto Map(F func, ROOT::TSeq<INTEGER> args) -> std::vector<typename std::result_of<F(INTEGER)>::type>;
76 /// \cond
77 template<class F, class T, class Cond = noReferenceCond<F, T>>
78 auto Map(F func, std::initializer_list<T> args) -> std::vector<typename std::result_of<F(T)>::type>;
79 /// \endcond
80 template<class F, class T, class Cond = noReferenceCond<F, T>>
81 auto Map(F func, std::vector<T> &args) -> std::vector<typename std::result_of<F(T)>::type>;
82
83 // // MapReduce
84 // // the late return types also check at compile-time whether redfunc is compatible with func,
85 // // other than checking that func is compatible with the type of arguments.
86 // // a static_assert check in TExecutor<subc>::Reduce is used to check that redfunc is compatible with the type returned by func
87 template<class F, class INTEGER, class R, class Cond = noReferenceCond<F, INTEGER>>
88 auto MapReduce(F func, ROOT::TSeq<INTEGER> args, R redfunc) -> typename std::result_of<F(INTEGER)>::type;
89 /// \cond
90 template<class F, class T, class R, class Cond = noReferenceCond<F, T>>
91 auto MapReduce(F func, std::initializer_list<T> args, R redfunc) -> typename std::result_of<F(T)>::type;
92 /// \endcond
93 template<class F, class T, class Cond = noReferenceCond<F, T>>
94 T* MapReduce(F func, std::vector<T*> &args);
95
96 template<class T> T* Reduce(const std::vector<T*> &mergeObjs);
97
98private:
99 inline subc & Derived()
100 {
101 return *static_cast<subc*>(this);
102 }
103};
104
105//////////////////////////////////////////////////////////////////////////
106/// Execute func (with no arguments) nTimes in parallel.
107/// A vector containg executions' results is returned.
108/// Functions that take more than zero arguments can be executed (with
109/// fixed arguments) by wrapping them in a lambda or with std::bind.
110template<class subc> template<class F, class Cond>
111auto TExecutor<subc>::Map(F func, unsigned nTimes) -> std::vector<typename std::result_of<F()>::type>
112{
113 return Derived().Map(func, nTimes);
114}
115
116//////////////////////////////////////////////////////////////////////////
117/// Execute func in parallel, taking an element of a
118/// sequence as argument. Divides and groups the executions in nChunks with partial reduction;
119/// A vector containg partial reductions' results is returned.
120template<class subc> template<class F, class INTEGER, class Cond>
121auto TExecutor<subc>::Map(F func, ROOT::TSeq<INTEGER> args) -> std::vector<typename std::result_of<F(INTEGER)>::type>
122{
123 return Derived().Map(func, args);
124}
125
126//////////////////////////////////////////////////////////////////////////
127/// Execute func in parallel, taking an element of the std::initializer_list
128/// as argument. Divides and groups the executions in nChunks with partial reduction;
129/// A vector containg partial reductions' results is returned.
130template<class subc> template<class F, class T, class Cond>
131auto TExecutor<subc>::Map(F func, std::initializer_list<T> args) -> std::vector<typename std::result_of<F(T)>::type>
132{
133 std::vector<T> vargs(std::move(args));
134 return Map(func, vargs);
135}
136
137//////////////////////////////////////////////////////////////////////////
138/// Execute func in parallel, taking an element of an
139/// std::vector as argument.
140/// A vector containg executions' results is returned.
141// actual implementation of the Map method. all other calls with arguments eventually
142// call this one
143template<class subc> template<class F, class T, class Cond>
144auto TExecutor<subc>::Map(F func, std::vector<T> &args) -> std::vector<typename std::result_of<F(T)>::type>
145{
146 return Derived().Map(func, args);
147}
148
149//////////////////////////////////////////////////////////////////////////
150/// This method behaves just like Map, but an additional redfunc function
151/// must be provided. redfunc is applied to the vector Map would return and
152/// must return the same type as func. In practice, redfunc can be used to
153/// "squash" the vector returned by Map into a single object by merging,
154/// adding, mixing the elements of the vector.
155template<class subc> template<class F, class INTEGER, class R, class Cond>
156auto TExecutor<subc>::MapReduce(F func, ROOT::TSeq<INTEGER> args, R redfunc) -> typename std::result_of<F(INTEGER)>::type
157{
158 std::vector<INTEGER> vargs(args.size());
159 std::copy(args.begin(), args.end(), vargs.begin());
160 return Derived().MapReduce(func, vargs, redfunc);
161}
162
163template<class subc> template<class F, class T, class R, class Cond>
164auto TExecutor<subc>::MapReduce(F func, std::initializer_list<T> args, R redfunc) -> typename std::result_of<F(T)>::type
165{
166 std::vector<T> vargs(std::move(args));
167 return Derived().MapReduce(func, vargs, redfunc);
168}
169
170template<class subc> template<class F, class T, class Cond>
171T* TExecutor<subc>::MapReduce(F func, std::vector<T*> &args)
172{
173 return Derived().Reduce(Map(func, args));
174}
175
176//////////////////////////////////////////////////////////////////////////
177/// "Reduce" an std::vector into a single object by using the object's Merge
178//Reduction for objects with the Merge() method
179template<class subc> template<class T>
180T* TExecutor<subc>::Reduce(const std::vector<T*> &mergeObjs)
181{
182 TList l;
183 for(unsigned i =1; i<mergeObjs.size(); i++){
184 l.Add(mergeObjs[i]);
185 }
186 // use clone to return a new object
187 auto retHist = dynamic_cast<T*>((mergeObjs.front())->Clone());
188 if (retHist) retHist->Merge(&l);
189 return retHist;
190}
191
192} // end namespace ROOT
193
194#endif
#define R(a, b, c, d, e, f, g, h, i)
Definition: RSha256.hxx:110
int type
Definition: TGX11.cxx:120
This class defines an interface to execute the same task multiple times in parallel,...
Definition: TExecutor.hxx:61
TExecutor()=default
auto Map(F func, unsigned nTimes) -> std::vector< typename std::result_of< F()>::type >
Execute func (with no arguments) nTimes in parallel.
Definition: TExecutor.hxx:111
auto Map(F func, ROOT::TSeq< INTEGER > args) -> std::vector< typename std::result_of< F(INTEGER)>::type >
Execute func in parallel, taking an element of a sequence as argument.
Definition: TExecutor.hxx:121
auto Map(F func, std::vector< T > &args) -> std::vector< typename std::result_of< F(T)>::type >
Execute func in parallel, taking an element of an std::vector as argument.
Definition: TExecutor.hxx:144
T * MapReduce(F func, std::vector< T * > &args)
Definition: TExecutor.hxx:171
typename std::enable_if<"Function can't return a reference" &&!(std::is_reference< typename std::result_of< F(T...)>::type >::value)>::type noReferenceCond
Definition: TExecutor.hxx:67
auto MapReduce(F func, ROOT::TSeq< INTEGER > args, R redfunc) -> typename std::result_of< F(INTEGER)>::type
This method behaves just like Map, but an additional redfunc function must be provided.
Definition: TExecutor.hxx:156
subc & Derived()
Definition: TExecutor.hxx:99
TExecutor(size_t)
Definition: TExecutor.hxx:64
T * Reduce(const std::vector< T * > &mergeObjs)
"Reduce" an std::vector into a single object by using the object's Merge
Definition: TExecutor.hxx:180
A pseudo container class which is a generator of indices.
Definition: TSeq.hxx:66
A doubly linked list.
Definition: TList.h:44
#define F(x, y, z)
double T(double x)
Definition: ChebyshevPol.h:34
auto Map(Args &&... args) -> decltype(ROOT::Detail::VecOps::MapFromTuple(std::forward_as_tuple(args...), std::make_index_sequence< sizeof...(args) - 1 >()))
Create new collection applying a callable to the elements of the input collection.
Definition: RVec.hxx:910
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Definition: StringConv.hxx:21
auto * l
Definition: textangle.C:4