1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // accumulator_set.hpp |
3 | // |
4 | // Copyright 2005 Eric Niebler. Distributed under the Boost |
5 | // Software License, Version 1.0. (See accompanying file |
6 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
7 | |
8 | #ifndef BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATOR_SET_HPP_EAN_28_10_2005 |
9 | #define BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATOR_SET_HPP_EAN_28_10_2005 |
10 | |
11 | #include <boost/version.hpp> |
12 | #include <boost/mpl/apply.hpp> |
13 | #include <boost/mpl/assert.hpp> |
14 | #include <boost/mpl/protect.hpp> |
15 | #include <boost/mpl/identity.hpp> |
16 | #include <boost/mpl/is_sequence.hpp> |
17 | #include <boost/type_traits/is_same.hpp> |
18 | #include <boost/type_traits/is_base_and_derived.hpp> |
19 | #include <boost/parameter/parameters.hpp> |
20 | #include <boost/preprocessor/repetition/repeat_from_to.hpp> |
21 | #include <boost/preprocessor/repetition/enum_binary_params.hpp> |
22 | #include <boost/accumulators/accumulators_fwd.hpp> |
23 | #include <boost/accumulators/framework/depends_on.hpp> |
24 | #include <boost/accumulators/framework/accumulator_concept.hpp> |
25 | #include <boost/accumulators/framework/parameters/accumulator.hpp> |
26 | #include <boost/accumulators/framework/parameters/sample.hpp> |
27 | #include <boost/accumulators/framework/accumulators/external_accumulator.hpp> |
28 | #include <boost/accumulators/framework/accumulators/droppable_accumulator.hpp> |
29 | #include <boost/fusion/include/any.hpp> |
30 | #include <boost/fusion/include/find_if.hpp> |
31 | #include <boost/fusion/include/for_each.hpp> |
32 | #include <boost/fusion/include/filter_view.hpp> |
33 | |
34 | namespace boost { namespace accumulators |
35 | { |
36 | |
37 | namespace detail |
38 | { |
39 | /////////////////////////////////////////////////////////////////////////////// |
40 | // accumulator_visitor |
41 | // wrap a boost::parameter argument pack in a Fusion extractor object |
42 | template<typename Args> |
43 | struct accumulator_visitor |
44 | { |
45 | explicit accumulator_visitor(Args const &a) |
46 | : args(a) |
47 | { |
48 | } |
49 | |
50 | template<typename Accumulator> |
51 | void operator ()(Accumulator &accumulator) const |
52 | { |
53 | accumulator(this->args); |
54 | } |
55 | |
56 | private: |
57 | accumulator_visitor &operator =(accumulator_visitor const &); |
58 | Args const &args; |
59 | }; |
60 | |
61 | template<typename Args> |
62 | inline accumulator_visitor<Args> const make_accumulator_visitor(Args const &args) |
63 | { |
64 | return accumulator_visitor<Args>(args); |
65 | } |
66 | |
67 | typedef |
68 | parameter::parameters< |
69 | parameter::required<tag::accumulator> |
70 | , parameter::optional<tag::sample> |
71 | // ... and others which are not specified here... |
72 | > |
73 | accumulator_params; |
74 | |
75 | /////////////////////////////////////////////////////////////////////////////// |
76 | // accumulator_set_base |
77 | struct accumulator_set_base |
78 | { |
79 | }; |
80 | |
81 | /////////////////////////////////////////////////////////////////////////////// |
82 | // is_accumulator_set |
83 | template<typename T> |
84 | struct is_accumulator_set |
85 | : is_base_and_derived<accumulator_set_base, T> |
86 | { |
87 | }; |
88 | |
89 | } // namespace detail |
90 | |
91 | #ifdef _MSC_VER |
92 | #pragma warning(push) |
93 | #pragma warning(disable: 4355) // warning C4355: 'this' : used in base member initializer list |
94 | #endif |
95 | |
96 | /////////////////////////////////////////////////////////////////////////////// |
97 | /// \brief A set of accumulators. |
98 | /// |
99 | /// accumulator_set resolves the dependencies between features and ensures that |
100 | /// the accumulators in the set are updated in the proper order. |
101 | /// |
102 | /// acccumulator_set provides a general mechanism to visit the accumulators |
103 | /// in the set in order, with or without a filter. You can also fetch a reference |
104 | /// to an accumulator that corresponds to a feature. |
105 | /// |
106 | template<typename Sample, typename Features, typename Weight> |
107 | struct accumulator_set |
108 | : detail::accumulator_set_base |
109 | { |
110 | typedef Sample sample_type; ///< The type of the samples that will be accumulated |
111 | typedef Features features_type; ///< An MPL sequence of the features that should be accumulated. |
112 | typedef Weight weight_type; ///< The type of the weight parameter. Must be a scalar. Defaults to void. |
113 | |
114 | /// INTERNAL ONLY |
115 | /// |
116 | typedef |
117 | typename detail::make_accumulator_tuple< |
118 | Features |
119 | , Sample |
120 | , Weight |
121 | >::type |
122 | accumulators_mpl_vector; |
123 | |
124 | // generate a fusion::list of accumulators |
125 | /// INTERNAL ONLY |
126 | /// |
127 | typedef |
128 | typename detail::meta::make_acc_list< |
129 | accumulators_mpl_vector |
130 | >::type |
131 | accumulators_type; |
132 | |
133 | /// INTERNAL ONLY |
134 | /// |
135 | //BOOST_MPL_ASSERT((mpl::is_sequence<accumulators_type>)); |
136 | |
137 | /////////////////////////////////////////////////////////////////////////////// |
138 | /// default-construct all contained accumulators |
139 | accumulator_set() |
140 | : accumulators( |
141 | detail::make_acc_list( |
142 | accumulators_mpl_vector() |
143 | , detail::accumulator_params()(*this) |
144 | ) |
145 | ) |
146 | { |
147 | // Add-ref the Features that the user has specified |
148 | this->template visit_if<detail::contains_feature_of_<Features> >( |
149 | detail::make_add_ref_visitor(detail::accumulator_params()(*this)) |
150 | ); |
151 | } |
152 | |
153 | /// \overload |
154 | /// |
155 | /// \param a1 Optional named parameter to be passed to all the accumulators |
156 | template<typename A1> |
157 | explicit accumulator_set(A1 const &a1) |
158 | : accumulators( |
159 | detail::make_acc_list( |
160 | accumulators_mpl_vector() |
161 | , detail::accumulator_params()(*this, a1) |
162 | ) |
163 | ) |
164 | { |
165 | // Add-ref the Features that the user has specified |
166 | this->template visit_if<detail::contains_feature_of_<Features> >( |
167 | detail::make_add_ref_visitor(detail::accumulator_params()(*this)) |
168 | ); |
169 | } |
170 | |
171 | // ... other overloads generated by Boost.Preprocessor: |
172 | |
173 | /// INTERNAL ONLY |
174 | /// |
175 | #define BOOST_ACCUMULATORS_ACCUMULATOR_SET_CTOR(z, n, _) \ |
176 | template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ |
177 | accumulator_set(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a)) \ |
178 | : accumulators( \ |
179 | detail::make_acc_list( \ |
180 | accumulators_mpl_vector() \ |
181 | , detail::accumulator_params()( \ |
182 | *this BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \ |
183 | ) \ |
184 | ) \ |
185 | ) \ |
186 | { \ |
187 | /* Add-ref the Features that the user has specified */ \ |
188 | this->template visit_if<detail::contains_feature_of_<Features> >( \ |
189 | detail::make_add_ref_visitor(detail::accumulator_params()(*this)) \ |
190 | ); \ |
191 | } |
192 | |
193 | /// INTERNAL ONLY |
194 | /// |
195 | BOOST_PP_REPEAT_FROM_TO( |
196 | 2 |
197 | , BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS) |
198 | , BOOST_ACCUMULATORS_ACCUMULATOR_SET_CTOR |
199 | , _ |
200 | ) |
201 | |
202 | #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED |
203 | /// \overload |
204 | /// |
205 | template<typename A1, typename A2, ...> |
206 | accumulator_set(A1 const &a1, A2 const &a2, ...); |
207 | #endif |
208 | |
209 | // ... other overloads generated by Boost.Preprocessor below ... |
210 | |
211 | /////////////////////////////////////////////////////////////////////////////// |
212 | /// Visitation |
213 | /// \param func UnaryFunction which is invoked with each accumulator in turn. |
214 | template<typename UnaryFunction> |
215 | void visit(UnaryFunction const &func) |
216 | { |
217 | fusion::for_each(this->accumulators, func); |
218 | } |
219 | |
220 | /////////////////////////////////////////////////////////////////////////////// |
221 | /// Conditional visitation |
222 | /// \param func UnaryFunction which is invoked with each accumulator in turn, |
223 | /// provided the accumulator satisfies the MPL predicate FilterPred. |
224 | template<typename FilterPred, typename UnaryFunction> |
225 | void visit_if(UnaryFunction const &func) |
226 | { |
227 | fusion::filter_view<accumulators_type, FilterPred> filtered_accs(this->accumulators); |
228 | fusion::for_each(filtered_accs, func); |
229 | } |
230 | |
231 | /////////////////////////////////////////////////////////////////////////////// |
232 | /// The return type of the operator() overloads is void. |
233 | typedef void result_type; |
234 | |
235 | /////////////////////////////////////////////////////////////////////////////// |
236 | /// Accumulation |
237 | /// \param a1 Optional named parameter to be passed to all the accumulators |
238 | void operator ()() |
239 | { |
240 | this->visit( |
241 | detail::make_accumulator_visitor( |
242 | detail::accumulator_params()(*this) |
243 | ) |
244 | ); |
245 | } |
246 | |
247 | template<typename A1> |
248 | void operator ()(A1 const &a1) |
249 | { |
250 | this->visit( |
251 | detail::make_accumulator_visitor( |
252 | detail::accumulator_params()(*this, a1) |
253 | ) |
254 | ); |
255 | } |
256 | |
257 | // ... other overloads generated by Boost.Preprocessor: |
258 | |
259 | /// INTERNAL ONLY |
260 | /// |
261 | #define BOOST_ACCUMULATORS_ACCUMULATOR_SET_FUN_OP(z, n, _) \ |
262 | template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ |
263 | void operator ()(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a)) \ |
264 | { \ |
265 | this->visit( \ |
266 | detail::make_accumulator_visitor( \ |
267 | detail::accumulator_params()( \ |
268 | *this BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \ |
269 | ) \ |
270 | ) \ |
271 | ); \ |
272 | } |
273 | |
274 | /// INTERNAL ONLY |
275 | /// |
276 | BOOST_PP_REPEAT_FROM_TO( |
277 | 2 |
278 | , BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS) |
279 | , BOOST_ACCUMULATORS_ACCUMULATOR_SET_FUN_OP |
280 | , _ |
281 | ) |
282 | |
283 | #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED |
284 | /// \overload |
285 | /// |
286 | template<typename A1, typename A2, ...> |
287 | void operator ()(A1 const &a1, A2 const &a2, ...); |
288 | #endif |
289 | |
290 | /////////////////////////////////////////////////////////////////////////////// |
291 | /// Extraction |
292 | template<typename Feature> |
293 | struct apply |
294 | : fusion::result_of::value_of< |
295 | typename fusion::result_of::find_if< |
296 | accumulators_type |
297 | , detail::matches_feature<Feature> |
298 | >::type |
299 | > |
300 | { |
301 | }; |
302 | |
303 | /////////////////////////////////////////////////////////////////////////////// |
304 | /// Extraction |
305 | template<typename Feature> |
306 | typename apply<Feature>::type &() |
307 | { |
308 | return *fusion::find_if<detail::matches_feature<Feature> >(this->accumulators); |
309 | } |
310 | |
311 | /// \overload |
312 | template<typename Feature> |
313 | typename apply<Feature>::type const &() const |
314 | { |
315 | return *fusion::find_if<detail::matches_feature<Feature> >(this->accumulators); |
316 | } |
317 | |
318 | /////////////////////////////////////////////////////////////////////////////// |
319 | /// Drop |
320 | template<typename Feature> |
321 | void drop() |
322 | { |
323 | // You can only drop the features that you have specified explicitly |
324 | typedef typename apply<Feature>::type the_accumulator; |
325 | BOOST_MPL_ASSERT((detail::contains_feature_of<Features, the_accumulator>)); |
326 | |
327 | typedef |
328 | typename feature_of<typename as_feature<Feature>::type>::type |
329 | the_feature; |
330 | |
331 | (*fusion::find_if<detail::matches_feature<Feature> >(this->accumulators)) |
332 | .drop(detail::accumulator_params()(*this)); |
333 | |
334 | // Also drop accumulators that this feature depends on |
335 | typedef typename the_feature::dependencies dependencies; |
336 | this->template visit_if<detail::contains_feature_of_<dependencies> >( |
337 | detail::make_drop_visitor(detail::accumulator_params()(*this)) |
338 | ); |
339 | } |
340 | |
341 | private: |
342 | |
343 | accumulators_type accumulators; |
344 | }; |
345 | |
346 | #ifdef _MSC_VER |
347 | #pragma warning(pop) |
348 | #endif |
349 | |
350 | /////////////////////////////////////////////////////////////////////////////// |
351 | // find_accumulator |
352 | // find an accumulator in an accumulator_set corresponding to a feature |
353 | template<typename Feature, typename AccumulatorSet> |
354 | typename mpl::apply<AccumulatorSet, Feature>::type & |
355 | find_accumulator(AccumulatorSet &acc BOOST_ACCUMULATORS_PROTO_DISABLE_IF_IS_CONST(AccumulatorSet)) |
356 | { |
357 | return acc.template extract<Feature>(); |
358 | } |
359 | |
360 | /// \overload |
361 | template<typename Feature, typename AccumulatorSet> |
362 | typename mpl::apply<AccumulatorSet, Feature>::type const & |
363 | find_accumulator(AccumulatorSet const &acc) |
364 | { |
365 | return acc.template extract<Feature>(); |
366 | } |
367 | |
368 | /////////////////////////////////////////////////////////////////////////////// |
369 | // extract_result |
370 | // extract a result from an accumulator set |
371 | /// INTERNAL ONLY |
372 | /// |
373 | #define (z, n, _) \ |
374 | template< \ |
375 | typename Feature \ |
376 | , typename AccumulatorSet \ |
377 | BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, typename A) \ |
378 | > \ |
379 | typename mpl::apply<AccumulatorSet, Feature>::type::result_type \ |
380 | ( \ |
381 | AccumulatorSet const &acc \ |
382 | BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(z, n, A, const &a) \ |
383 | ) \ |
384 | { \ |
385 | return find_accumulator<Feature>(acc).result( \ |
386 | detail::accumulator_params()( \ |
387 | acc \ |
388 | BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \ |
389 | ) \ |
390 | ); \ |
391 | } |
392 | |
393 | BOOST_PP_REPEAT( |
394 | BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS) |
395 | , BOOST_ACCUMULATORS_EXTRACT_RESULT_FUN |
396 | , _ |
397 | ) |
398 | |
399 | }} // namespace boost::accumulators |
400 | |
401 | #endif |
402 | |