1/*=============================================================================
2 Copyright (c) 2001-2007 Joel de Guzman
3
4 Distributed under the Boost Software License, Version 1.0. (See accompanying
5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6==============================================================================*/
7
8#include <boost/phoenix.hpp>
9
10struct omp_for_eval
11{
12 typedef void result_type;
13
14 template <typename Init, typename Cond, typename Step, typename Do, typename Context>
15 result_type
16 operator()(
17 Init const& init
18 , Cond const& cond
19 , Step const& step
20 , Do const& do_
21 , Context & ctx
22 ) const
23 {
24#pragma omp parallel
25 for(
26 boost::phoenix::eval(init, ctx);
27 boost::phoenix::eval(cond, ctx);
28 boost::phoenix::eval(step, ctx)
29 )
30 {
31 boost::phoenix::eval(do_, ctx);
32 }
33 }
34};
35
36
37////////////////////////////////////////////////////////////////////////////////
38// Define new custom expression
39BOOST_PHOENIX_DEFINE_EXPRESSION(
40 (omp_for)
41 , (boost::phoenix::meta_grammar) // Cond
42 (boost::phoenix::meta_grammar) // Init
43 (boost::phoenix::meta_grammar) // Step
44 (boost::phoenix::meta_grammar) // Do
45)
46
47namespace boost { namespace phoenix
48{
49 template <>
50 struct default_actions::when< ::rule::omp_for>
51 : boost::phoenix::call< ::omp_for_eval>
52 {};
53}}
54
55template <typename Init, typename Cond, typename Step>
56struct omp_for_gen
57{
58 omp_for_gen(Init const& init, Cond const& cond, Step const& step)
59 : init(init), cond(cond), step(step) {}
60
61 template <typename Do>
62 typename result_of::make_omp_for<Init, Cond, Step, Do>::type const
63 operator[](Do const& do_) const
64 {
65 return make_omp_for(init, cond, step, do_);
66 }
67
68 Init init;
69 Cond cond;
70 Step step;
71};
72
73template <typename Init, typename Cond, typename Step>
74inline
75omp_for_gen<Init, Cond, Step> const
76omp_for(Init const& init, Cond const& cond, Step const& step)
77{
78 return omp_for_gen<Init, Cond, Step>(init, cond, step);
79}
80////////////////////////////////////////////////////////////////////////////////
81
82
83////////////////////////////////////////////////////////////////////////////////
84// Define new evaluation scheme
85
86struct parallel_actions
87{
88 template <typename Rule>
89 struct when
90 : boost::phoenix::default_actions::when<Rule>
91 {};
92};
93
94template <>
95struct parallel_actions::when<boost::phoenix::rule::for_>
96 : boost::phoenix::call<omp_for_eval>
97{};
98
99// Doing the same as actor<Expr>::operator
100template <typename Expr, typename A0, typename A1, typename A2>
101typename boost::phoenix::result_of::eval<
102 Expr const &
103 , typename boost::phoenix::result_of::make_context<
104 typename boost::phoenix::result_of::make_env<
105 Expr const *
106 , A0 &
107 , A1 &
108 , A2 &
109 >::type
110 , parallel_actions
111 >::type
112>::type
113parallel_eval(Expr & expr, A0 & a0, A1 & a1, A2 & a2)
114{
115 Expr const * this_ = boost::addressof(expr);
116 return
117 boost::phoenix::eval(
118 expr
119 , boost::phoenix::make_context(
120 boost::phoenix::make_env(this_, a0, a1, a2)
121 , parallel_actions()
122 )
123 );
124}
125
126// changing evaluation mechanism on the fly
127BOOST_PHOENIX_DEFINE_EXPRESSION(
128 (parallel)
129 , (boost::phoenix::meta_grammar)
130)
131
132namespace boost { namespace phoenix
133{
134 template <>
135 struct default_actions::when< ::rule::parallel>
136 : proto::call<
137 evaluator(
138 proto::_child0
139 , functional::make_context(
140 _env
141 , parallel_actions()
142 )
143 , unused()//mpl::void_()
144 )
145 >
146 {};
147}}
148
149template <typename Expr>
150typename result_of::make_parallel<Expr>::type
151parallel(Expr const & expr)
152{
153 return make_parallel(expr);
154}
155////////////////////////////////////////////////////////////////////////////////
156
157
158#include <vector>
159#include <iostream>
160
161int main()
162{
163 using boost::phoenix::arg_names::_1;
164 using boost::phoenix::arg_names::_2;
165 using boost::phoenix::arg_names::_3;
166 using boost::phoenix::local_names::_a;
167 using boost::phoenix::local_names::_b;
168 using boost::phoenix::local_names::_c;
169 using boost::phoenix::let;
170 using boost::phoenix::bind;
171 using boost::phoenix::lambda;
172 using boost::phoenix::nothing;
173
174 const int NUM = 1;
175
176 {
177 std::vector<int> a(NUM, 1);
178 std::vector<int> b(NUM, 2);
179 std::vector<int> c(NUM, 0);
180
181 (
182 let(_a = begin(_1), _b = begin(_2), _c = begin(_3))
183 [
184 for_(nothing, _a != end(_1), (++_a, ++_b, ++_c))
185 [
186 *_c = *_a + *_b
187 ]
188 ]
189 , std::cout << accumulate(a0: _3, a1: 0) << "\n"
190 )(a, b, c);
191 }
192
193 {
194 std::vector<int> a(NUM, 1);
195 std::vector<int> b(NUM, 2);
196 std::vector<int> c(NUM, 0);
197
198 (
199 let(_a = begin(_1), _b = begin(_2), _c = begin(_3))
200 [
201 omp_for(nothing, _a != end(_1), (++_a, ++_b, ++_c))
202 [
203 *_c = *_a + *_b
204 ]
205 , std::cout << accumulate(a0: _3, a1: 0) << "\n"
206 ]
207 )(a, b, c);
208 }
209
210 {
211 std::vector<int> a(NUM, 1);
212 std::vector<int> b(NUM, 2);
213 std::vector<int> c(NUM, 0);
214
215 parallel_eval(
216 let(_a = begin(_1), _b = begin(_2), _c = begin(_3))
217 [
218 for_(nothing, _a != end(_1), (++_a, ++_b, ++_c))
219 [
220 *_c = *_a + *_b
221 ]
222 , std::cout << accumulate(a0: _3, a1: 0) << "\n"
223 ]
224 , a, b, c);
225 }
226
227 {
228 std::vector<int> a(NUM, 1);
229 std::vector<int> b(NUM, 2);
230 std::vector<int> c(NUM, 0);
231
232 (
233 let(_a = begin(_1), _b = begin(_2), _c = begin(_3))
234 [
235 parallel(
236 for_(nothing, _a != end(_1), (++_a, ++_b, ++_c))
237 [
238 *_c = *_a + *_b
239 ]
240 )
241 ]
242 , std::cout << accumulate(a0: _3, a1: 0) << "\n"
243 )(a, b, c);
244 }
245}
246

source code of boost/libs/phoenix/example/parallel_for.cpp