Logo ROOT   6.07/09
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 "TCollection.h"
16 #include "ROOT/TSeq.hxx"
17 
18 namespace ROOT {
19 
20 template<class subc>
21 class TExecutor {
22 public:
23  explicit TExecutor() = default;
24  explicit TExecutor(size_t /* nThreads */ ){};
25 
26  template< class F, class... T>
27  using noReferenceCond = typename std::enable_if<"Function can't return a reference" && !(std::is_reference<typename std::result_of<F(T...)>::type>::value)>::type;
28 
29  // // Map
30  // //these late return types allow for a compile-time check of compatibility between function signatures and args,
31  // //and a compile-time check that the argument list implements a front() method (all STL sequence containers have it)
32  template<class F, class Cond = noReferenceCond<F>>
33  auto Map(F func, unsigned nTimes) -> std::vector<typename std::result_of<F()>::type>;
34  template<class F, class T, class Cond = noReferenceCond<F, typename T::value_type>>
35  auto Map(F func, T &args) -> std::vector < decltype(++(args.begin()), args.end(), func(args.front()))>;
36  // /// \cond doxygen should ignore these methods
37  template<class F, class INTEGER, class Cond = noReferenceCond<F, INTEGER>>
39  template<class F, class Cond = noReferenceCond<F, TObject*>>
41  template<class F, class T, class Cond = noReferenceCond<F, T>>
42  auto Map(F func, std::initializer_list<T> args) -> std::vector<typename std::result_of<F(T)>::type>;
43  template<class F, class T, class Cond = noReferenceCond<F, T>>
44  auto Map(F func, std::vector<T> &args) -> std::vector<typename std::result_of<F(T)>::type>;
45  // // // / \endcond
46 
47  // // MapReduce
48  // // the late return types also check at compile-time whether redfunc is compatible with func,
49  // // other than checking that func is compatible with the type of arguments.
50  // // a static_assert check in TExecutor<subc>::Reduce is used to check that redfunc is compatible with the type returned by func
51  template<class F, class R, class Cond = noReferenceCond<F>>
52  auto MapReduce(F func, unsigned nTimes, R redfunc) -> typename std::result_of<F()>::type;
53  template<class F, class INTEGER, class R, class Cond = noReferenceCond<F, INTEGER>>
54  auto MapReduce(F func, ROOT::TSeq<INTEGER> args, R redfunc) -> typename std::result_of<F(INTEGER)>::type;
55  // /// \cond doxygen should ignore these methods
56  template<class F, class T, class R, class Cond = noReferenceCond<F, T>>
57  auto MapReduce(F func, std::initializer_list<T> args, R redfunc) -> typename std::result_of<F(T)>::type;
58  template<class F, class T, class R, class Cond = noReferenceCond<F, T>>
59  auto MapReduce(F func, std::vector<T> &args, R redfunc) -> typename std::result_of<F(T)>::type;
60  // /// \endcond
61 
62 protected:
63  template<class T, class R> auto Reduce(const std::vector<T> &objs, R redfunc) -> decltype(redfunc(objs));
64  template<class T, class BINARYOP> auto Reduce(const std::vector<T> &objs, BINARYOP redfunc) -> decltype(redfunc(objs.front(), objs.front()));
65 
66 private:
67  inline subc & Derived()
68  {
69  return *static_cast<subc*>(this);
70  }
71 };
72 
73 //////////////////////////////////////////////////////////////////////////
74 /// Execute func (with no arguments) nTimes in parallel.
75 /// A vector containg executions' results is returned.
76 /// Functions that take more than zero arguments can be executed (with
77 /// fixed arguments) by wrapping them in a lambda or with std::bind.
78 template<class subc> template<class F, class Cond>
80 {
81  return Derived().Map(func, nTimes);
82 }
83 
84 // //////////////////////////////////////////////////////////////////////////
85 // /// Execute func in parallel distributing the elements of the args collection between the workers.
86 // /// See class description for the valid types of collections and containers that can be used.
87 // /// A vector containing each execution's result is returned. The user is responsible of deleting
88 // /// objects that might be created upon the execution of func, returned objects included.
89 // /// **Note:** the collection of arguments is modified by Map and should be considered empty or otherwise
90 // /// invalidated after Map's execution (std::move might be applied to it).
91 
92 // tell doxygen to ignore this (\endcond closes the statement)
93 /// \cond
94 template<class subc> template<class F, class INTEGER, class Cond>
96 {
97  return Derived().Map(func, args);
98 }
99 
100 template<class subc> template<class F, class T, class Cond>
101 auto TExecutor<subc>::Map(F func, std::initializer_list<T> args) -> std::vector<typename std::result_of<F(T)>::type>
102 {
103  std::vector<T> vargs(std::move(args));
104  const auto &reslist = Map(func, vargs);
105  return reslist;
106 }
107 
108 // actual implementation of the Map method. all other calls with arguments eventually
109 // call this one
110 
111 template<class subc> template<class F, class T, class Cond>
113 {
114  return Derived().Map(func, args);
115 }
116 
117 // //////////////////////////////////////////////////////////////////////////
118 // /// This method behaves just like Map, but an additional redfunc function
119 // /// must be provided. redfunc is applied to the vector Map would return and
120 // /// must return the same type as func. In practice, redfunc can be used to
121 // /// "squash" the vector returned by Map into a single object by merging,
122 // /// adding, mixing the elements of the vector.
123 template<class subc> template<class F, class R, class Cond>
124 auto TExecutor<subc>::MapReduce(F func, unsigned nTimes, R redfunc) -> typename std::result_of<F()>::type
125 {
126  return Reduce(Map(func, nTimes), redfunc);
127 }
128 
129 //////////////////////////////////////////////////////////////////////////
130 /// This method behaves just like Map, but an additional redfunc function
131 /// must be provided. redfunc is applied to the vector Map would return and
132 /// must return the same type as func. In practice, redfunc can be used to
133 /// "squash" the vector returned by Map into a single object by merging,
134 /// adding, mixing the elements of the vector.
135 
136 /// \cond doxygen should ignore these methods
137 template<class subc> template<class F, class INTEGER, class R, class Cond>
139 {
140  return Reduce(Map(func, args), redfunc);
141 }
142 
143 template<class subc> template<class F, class T, class R, class Cond>
144 auto TExecutor<subc>::MapReduce(F func, std::initializer_list<T> args, R redfunc) -> typename std::result_of<F(T)>::type
145 {
146  return Reduce(Map(func, args), redfunc);
147 }
148 
149 template<class subc> template<class F, class T, class R, class Cond>
150 auto TExecutor<subc>::MapReduce(F func, std::vector<T> &args, R redfunc) -> typename std::result_of<F(T)>::type
151 {
152  return Reduce(Derived().Map(func, args), redfunc);
153 }
154 
155 /// \endcond
156 
157 /// Check that redfunc has the right signature and call it on objs
158 template<class subc> template<class T, class BINARYOP>
159 auto TExecutor<subc>::Reduce(const std::vector<T> &objs, BINARYOP redfunc) -> decltype(redfunc(objs.front(), objs.front()))
160 {
161  // check we can apply reduce to objs
162  static_assert(std::is_same<decltype(redfunc(objs.front(), objs.front())), T>::value, "redfunc does not have the correct signature");
163  return Derived().Reduce(objs, redfunc);
164 }
165 
166 template<class subc> template<class T, class R>
167 auto TExecutor<subc>::Reduce(const std::vector<T> &objs, R redfunc) -> decltype(redfunc(objs))
168 {
169  // check we can apply reduce to objs
170  static_assert(std::is_same<decltype(redfunc(objs)), T>::value, "redfunc does not have the correct signature");
171  return redfunc(objs);
172 }
173 
174 }
175 
176 #endif
This namespace contains pre-defined functions to be used in conjuction with TExecutor::Map and TExecu...
Definition: StringConv.hxx:21
double T(double x)
Definition: ChebyshevPol.h:34
TExecutor()=default
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:27
#define F(x, y, z)
auto Reduce(const std::vector< T > &objs, R redfunc) -> decltype(redfunc(objs))
Definition: TExecutor.hxx:167
Collection abstract base class.
Definition: TCollection.h:48
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:79
subc & Derived()
Definition: TExecutor.hxx:67
TExecutor(size_t)
Definition: TExecutor.hxx:24
A pseudo container class which is a generator of indices.
Definition: TSeq.hxx:66
int type
Definition: TGX11.cxx:120
auto MapReduce(F func, unsigned nTimes, R redfunc) -> typename std::result_of< F()>::type
double func(double *x, double *p)
Definition: stressTF1.cxx:213
TRandom3 R
a TMatrixD.
Definition: testIO.cxx:28