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/bool.hpp> |
13 | #include <boost/mpl/if.hpp> |
14 | #include <boost/mpl/apply.hpp> |
15 | #include <boost/mpl/assert.hpp> |
16 | #include <boost/mpl/protect.hpp> |
17 | #include <boost/mpl/identity.hpp> |
18 | #include <boost/mpl/is_sequence.hpp> |
19 | #include <boost/type_traits/is_same.hpp> |
20 | #include <boost/type_traits/is_base_of.hpp> |
21 | #include <boost/type_traits/remove_const.hpp> |
22 | #include <boost/type_traits/remove_reference.hpp> |
23 | #include <boost/core/enable_if.hpp> |
24 | #include <boost/parameter/is_argument_pack.hpp> |
25 | #include <boost/preprocessor/repetition/repeat_from_to.hpp> |
26 | #include <boost/preprocessor/repetition/enum_params.hpp> |
27 | #include <boost/preprocessor/repetition/enum_binary_params.hpp> |
28 | #include <boost/preprocessor/repetition/enum_trailing_params.hpp> |
29 | #include <boost/accumulators/accumulators_fwd.hpp> |
30 | #include <boost/accumulators/framework/depends_on.hpp> |
31 | #include <boost/accumulators/framework/accumulator_concept.hpp> |
32 | #include <boost/accumulators/framework/parameters/accumulator.hpp> |
33 | #include <boost/accumulators/framework/parameters/sample.hpp> |
34 | #include <boost/accumulators/framework/accumulators/external_accumulator.hpp> |
35 | #include <boost/accumulators/framework/accumulators/droppable_accumulator.hpp> |
36 | #include <boost/fusion/include/any.hpp> |
37 | #include <boost/fusion/include/find_if.hpp> |
38 | #include <boost/fusion/include/for_each.hpp> |
39 | #include <boost/fusion/include/filter_view.hpp> |
40 | |
41 | namespace boost { namespace accumulators |
42 | { |
43 | |
44 | namespace detail |
45 | { |
46 | /////////////////////////////////////////////////////////////////////////////// |
47 | // accumulator_visitor |
48 | // wrap a boost::parameter argument pack in a Fusion extractor object |
49 | template<typename Args> |
50 | struct accumulator_visitor |
51 | { |
52 | explicit accumulator_visitor(Args const &a) |
53 | : args(a) |
54 | { |
55 | } |
56 | |
57 | accumulator_visitor(accumulator_visitor const &other) |
58 | : args(other.args) |
59 | { |
60 | } |
61 | |
62 | template<typename Accumulator> |
63 | void operator ()(Accumulator &accumulator) const |
64 | { |
65 | accumulator(this->args); |
66 | } |
67 | |
68 | private: |
69 | BOOST_DELETED_FUNCTION(accumulator_visitor &operator =(accumulator_visitor const &)) |
70 | Args const &args; |
71 | }; |
72 | |
73 | template<typename Args> |
74 | inline accumulator_visitor<Args> const make_accumulator_visitor(Args const &args) |
75 | { |
76 | return accumulator_visitor<Args>(args); |
77 | } |
78 | |
79 | /////////////////////////////////////////////////////////////////////////////// |
80 | // accumulator_set_base |
81 | struct accumulator_set_base |
82 | { |
83 | }; |
84 | |
85 | /////////////////////////////////////////////////////////////////////////////// |
86 | // is_accumulator_set |
87 | template<typename T> |
88 | struct is_accumulator_set |
89 | : mpl::if_< |
90 | boost::is_base_of< |
91 | accumulator_set_base |
92 | , typename boost::remove_const< |
93 | typename boost::remove_reference<T>::type |
94 | >::type |
95 | > |
96 | , mpl::true_ |
97 | , mpl::false_ |
98 | >::type |
99 | { |
100 | }; |
101 | |
102 | // function object that serialize an accumulator |
103 | template<typename Archive> |
104 | struct serialize_accumulator |
105 | { |
106 | serialize_accumulator(Archive & _ar, const unsigned int _file_version) : |
107 | ar(_ar), file_version(_file_version) |
108 | {} |
109 | |
110 | template<typename Accumulator> |
111 | void operator ()(Accumulator &accumulator) |
112 | { |
113 | accumulator.serialize(ar, file_version); |
114 | } |
115 | |
116 | private: |
117 | Archive& ar; |
118 | const unsigned int file_version; |
119 | }; |
120 | |
121 | } // namespace detail |
122 | |
123 | #ifdef _MSC_VER |
124 | #pragma warning(push) |
125 | #pragma warning(disable: 4355) // warning C4355: 'this' : used in base member initializer list |
126 | #endif |
127 | |
128 | /////////////////////////////////////////////////////////////////////////////// |
129 | /// \brief A set of accumulators. |
130 | /// |
131 | /// accumulator_set resolves the dependencies between features and ensures that |
132 | /// the accumulators in the set are updated in the proper order. |
133 | /// |
134 | /// acccumulator_set provides a general mechanism to visit the accumulators |
135 | /// in the set in order, with or without a filter. You can also fetch a reference |
136 | /// to an accumulator that corresponds to a feature. |
137 | /// |
138 | template<typename Sample, typename Features, typename Weight> |
139 | struct accumulator_set |
140 | : detail::accumulator_set_base |
141 | { |
142 | typedef Sample sample_type; ///< The type of the samples that will be accumulated |
143 | typedef Features features_type; ///< An MPL sequence of the features that should be accumulated. |
144 | typedef Weight weight_type; ///< The type of the weight parameter. Must be a scalar. Defaults to void. |
145 | |
146 | /// INTERNAL ONLY |
147 | /// |
148 | typedef |
149 | typename detail::make_accumulator_tuple< |
150 | Features |
151 | , Sample |
152 | , Weight |
153 | >::type |
154 | accumulators_mpl_vector; |
155 | |
156 | // generate a fusion::list of accumulators |
157 | /// INTERNAL ONLY |
158 | /// |
159 | typedef |
160 | typename detail::meta::make_acc_list< |
161 | accumulators_mpl_vector |
162 | >::type |
163 | accumulators_type; |
164 | |
165 | /// INTERNAL ONLY |
166 | /// |
167 | //BOOST_MPL_ASSERT((mpl::is_sequence<accumulators_type>)); |
168 | |
169 | /////////////////////////////////////////////////////////////////////////////// |
170 | /// default-construct all contained accumulators |
171 | accumulator_set() |
172 | : accumulators( |
173 | detail::make_acc_list( |
174 | accumulators_mpl_vector() |
175 | , (boost::accumulators::accumulator = *this) |
176 | ) |
177 | ) |
178 | { |
179 | // Add-ref the Features that the user has specified |
180 | this->template visit_if<detail::contains_feature_of_<Features> >( |
181 | detail::make_add_ref_visitor(boost::accumulators::accumulator = *this) |
182 | ); |
183 | } |
184 | |
185 | /// \overload |
186 | /// |
187 | /// \param a1 Optional named parameter to be passed to all the accumulators |
188 | template<typename A1> |
189 | explicit accumulator_set( |
190 | A1 const &a1 |
191 | , typename boost::enable_if< |
192 | parameter::is_argument_pack<A1> |
193 | , detail::_enabler |
194 | >::type = detail::_enabler() |
195 | ) : accumulators( |
196 | detail::make_acc_list( |
197 | accumulators_mpl_vector() |
198 | , (boost::accumulators::accumulator = *this, a1) |
199 | ) |
200 | ) |
201 | { |
202 | // Add-ref the Features that the user has specified |
203 | this->template visit_if<detail::contains_feature_of_<Features> >( |
204 | detail::make_add_ref_visitor(boost::accumulators::accumulator = *this) |
205 | ); |
206 | } |
207 | |
208 | /// \overload |
209 | /// |
210 | /// \param a1 Optional sample parameter to be passed to all the accumulators |
211 | template<typename A1> |
212 | explicit accumulator_set( |
213 | A1 const &a1 |
214 | , typename boost::disable_if< |
215 | parameter::is_argument_pack<A1> |
216 | , detail::_enabler |
217 | >::type = detail::_enabler() |
218 | ) : accumulators( |
219 | detail::make_acc_list( |
220 | accumulators_mpl_vector() |
221 | , ( |
222 | boost::accumulators::accumulator = *this |
223 | , boost::accumulators::sample = a1 |
224 | ) |
225 | ) |
226 | ) |
227 | { |
228 | // Add-ref the Features that the user has specified |
229 | this->template visit_if<detail::contains_feature_of_<Features> >( |
230 | detail::make_add_ref_visitor(boost::accumulators::accumulator = *this) |
231 | ); |
232 | } |
233 | |
234 | // ... other overloads generated by Boost.Preprocessor: |
235 | |
236 | /// INTERNAL ONLY |
237 | /// |
238 | #define BOOST_ACCUMULATORS_ACCUMULATOR_SET_CTOR(z, n, _) \ |
239 | template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ |
240 | accumulator_set( \ |
241 | BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a) \ |
242 | , typename boost::enable_if< \ |
243 | parameter::is_argument_pack<A0> \ |
244 | , detail::_enabler \ |
245 | >::type = detail::_enabler() \ |
246 | ) : accumulators( \ |
247 | detail::make_acc_list( \ |
248 | accumulators_mpl_vector() \ |
249 | , ( \ |
250 | boost::accumulators::accumulator = *this \ |
251 | BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \ |
252 | ) \ |
253 | ) \ |
254 | ) \ |
255 | { \ |
256 | /* Add-ref the Features that the user has specified */ \ |
257 | this->template visit_if<detail::contains_feature_of_<Features> >( \ |
258 | detail::make_add_ref_visitor(boost::accumulators::accumulator = *this) \ |
259 | ); \ |
260 | } \ |
261 | template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ |
262 | accumulator_set( \ |
263 | BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a) \ |
264 | , typename boost::disable_if< \ |
265 | parameter::is_argument_pack<A0> \ |
266 | , detail::_enabler \ |
267 | >::type = detail::_enabler() \ |
268 | ) : accumulators( \ |
269 | detail::make_acc_list( \ |
270 | accumulators_mpl_vector() \ |
271 | , ( \ |
272 | boost::accumulators::accumulator = *this \ |
273 | , boost::accumulators::sample = BOOST_PP_ENUM_PARAMS_Z(z, n, a) \ |
274 | ) \ |
275 | ) \ |
276 | ) \ |
277 | { \ |
278 | /* Add-ref the Features that the user has specified */ \ |
279 | this->template visit_if<detail::contains_feature_of_<Features> >( \ |
280 | detail::make_add_ref_visitor(boost::accumulators::accumulator = *this) \ |
281 | ); \ |
282 | } |
283 | |
284 | /// INTERNAL ONLY |
285 | /// |
286 | BOOST_PP_REPEAT_FROM_TO( |
287 | 2 |
288 | , BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS) |
289 | , BOOST_ACCUMULATORS_ACCUMULATOR_SET_CTOR |
290 | , _ |
291 | ) |
292 | |
293 | #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED |
294 | /// \overload |
295 | /// |
296 | template<typename A1, typename A2, ...> |
297 | accumulator_set(A1 const &a1, A2 const &a2, ...); |
298 | #endif |
299 | |
300 | // ... other overloads generated by Boost.Preprocessor below ... |
301 | |
302 | /////////////////////////////////////////////////////////////////////////////// |
303 | /// Visitation |
304 | /// \param func UnaryFunction which is invoked with each accumulator in turn. |
305 | template<typename UnaryFunction> |
306 | void visit(UnaryFunction const &func) |
307 | { |
308 | fusion::for_each(this->accumulators, func); |
309 | } |
310 | |
311 | /////////////////////////////////////////////////////////////////////////////// |
312 | /// Conditional visitation |
313 | /// \param func UnaryFunction which is invoked with each accumulator in turn, |
314 | /// provided the accumulator satisfies the MPL predicate FilterPred. |
315 | template<typename FilterPred, typename UnaryFunction> |
316 | void visit_if(UnaryFunction const &func) |
317 | { |
318 | fusion::filter_view<accumulators_type, FilterPred> filtered_accs(this->accumulators); |
319 | fusion::for_each(filtered_accs, func); |
320 | } |
321 | |
322 | /////////////////////////////////////////////////////////////////////////////// |
323 | /// The return type of the operator() overloads is void. |
324 | typedef void result_type; |
325 | |
326 | /////////////////////////////////////////////////////////////////////////////// |
327 | /// Accumulation |
328 | /// \param a1 Optional named parameter to be passed to all the accumulators |
329 | void operator ()() |
330 | { |
331 | this->visit( |
332 | detail::make_accumulator_visitor( |
333 | boost::accumulators::accumulator = *this |
334 | ) |
335 | ); |
336 | } |
337 | |
338 | // ... other overloads generated by Boost.Preprocessor: |
339 | |
340 | /// INTERNAL ONLY |
341 | /// |
342 | #define BOOST_ACCUMULATORS_ACCUMULATOR_SET_FUN_OP(z, n, _) \ |
343 | template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ |
344 | void operator ()( \ |
345 | BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a) \ |
346 | , typename boost::enable_if< \ |
347 | parameter::is_argument_pack<A0> \ |
348 | , detail::_enabler \ |
349 | >::type = detail::_enabler() \ |
350 | ) \ |
351 | { \ |
352 | this->visit( \ |
353 | detail::make_accumulator_visitor( \ |
354 | ( \ |
355 | boost::accumulators::accumulator = *this \ |
356 | BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \ |
357 | ) \ |
358 | ) \ |
359 | ); \ |
360 | } \ |
361 | template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ |
362 | void operator ()( \ |
363 | BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a) \ |
364 | , typename boost::disable_if< \ |
365 | parameter::is_argument_pack<A0> \ |
366 | , detail::_enabler \ |
367 | >::type = detail::_enabler() \ |
368 | ) \ |
369 | { \ |
370 | this->visit( \ |
371 | detail::make_accumulator_visitor( \ |
372 | ( \ |
373 | boost::accumulators::accumulator = *this \ |
374 | , boost::accumulators::sample = BOOST_PP_ENUM_PARAMS_Z(z, n, a) \ |
375 | ) \ |
376 | ) \ |
377 | ); \ |
378 | } |
379 | |
380 | /// INTERNAL ONLY |
381 | /// |
382 | BOOST_PP_REPEAT_FROM_TO( |
383 | 1 |
384 | , BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS) |
385 | , BOOST_ACCUMULATORS_ACCUMULATOR_SET_FUN_OP |
386 | , _ |
387 | ) |
388 | |
389 | #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED |
390 | /// \overload |
391 | /// |
392 | template<typename A1, typename A2, ...> |
393 | void operator ()(A1 const &a1, A2 const &a2, ...); |
394 | #endif |
395 | |
396 | /////////////////////////////////////////////////////////////////////////////// |
397 | /// Extraction |
398 | template<typename Feature> |
399 | struct apply |
400 | : fusion::result_of::value_of< |
401 | typename fusion::result_of::find_if< |
402 | accumulators_type |
403 | , detail::matches_feature<Feature> |
404 | >::type |
405 | > |
406 | { |
407 | }; |
408 | |
409 | /////////////////////////////////////////////////////////////////////////////// |
410 | /// Extraction |
411 | template<typename Feature> |
412 | typename apply<Feature>::type &() |
413 | { |
414 | return *fusion::find_if<detail::matches_feature<Feature> >(this->accumulators); |
415 | } |
416 | |
417 | /// \overload |
418 | template<typename Feature> |
419 | typename apply<Feature>::type const &() const |
420 | { |
421 | return *fusion::find_if<detail::matches_feature<Feature> >(this->accumulators); |
422 | } |
423 | |
424 | /////////////////////////////////////////////////////////////////////////////// |
425 | /// Drop |
426 | template<typename Feature> |
427 | void drop() |
428 | { |
429 | // You can only drop the features that you have specified explicitly |
430 | typedef typename apply<Feature>::type the_accumulator; |
431 | BOOST_MPL_ASSERT((detail::contains_feature_of<Features, the_accumulator>)); |
432 | |
433 | typedef |
434 | typename feature_of<typename as_feature<Feature>::type>::type |
435 | the_feature; |
436 | |
437 | (*fusion::find_if<detail::matches_feature<Feature> >(this->accumulators)) |
438 | .drop(boost::accumulators::accumulator = *this); |
439 | |
440 | // Also drop accumulators that this feature depends on |
441 | typedef typename the_feature::dependencies dependencies; |
442 | this->template visit_if<detail::contains_feature_of_<dependencies> >( |
443 | detail::make_drop_visitor(boost::accumulators::accumulator = *this) |
444 | ); |
445 | } |
446 | |
447 | // make the accumulator set serializeable |
448 | template<class Archive> |
449 | void serialize(Archive & ar, const unsigned int file_version) |
450 | { |
451 | detail::serialize_accumulator<Archive> serializer(ar, file_version); |
452 | fusion::for_each(this->accumulators, serializer); |
453 | } |
454 | |
455 | private: |
456 | |
457 | accumulators_type accumulators; |
458 | }; |
459 | |
460 | #ifdef _MSC_VER |
461 | #pragma warning(pop) |
462 | #endif |
463 | |
464 | /////////////////////////////////////////////////////////////////////////////// |
465 | // find_accumulator |
466 | // find an accumulator in an accumulator_set corresponding to a feature |
467 | template<typename Feature, typename AccumulatorSet> |
468 | typename mpl::apply<AccumulatorSet, Feature>::type & |
469 | find_accumulator(AccumulatorSet &acc BOOST_ACCUMULATORS_PROTO_DISABLE_IF_IS_CONST(AccumulatorSet)) |
470 | { |
471 | return acc.template extract<Feature>(); |
472 | } |
473 | |
474 | /// \overload |
475 | template<typename Feature, typename AccumulatorSet> |
476 | typename mpl::apply<AccumulatorSet, Feature>::type const & |
477 | find_accumulator(AccumulatorSet const &acc) |
478 | { |
479 | return acc.template extract<Feature>(); |
480 | } |
481 | |
482 | template<typename Feature, typename AccumulatorSet> |
483 | typename mpl::apply<AccumulatorSet, Feature>::type::result_type |
484 | (AccumulatorSet const &acc) |
485 | { |
486 | return find_accumulator<Feature>(acc).result( |
487 | boost::accumulators::accumulator = acc |
488 | ); |
489 | } |
490 | |
491 | /////////////////////////////////////////////////////////////////////////////// |
492 | // extract_result |
493 | // extract a result from an accumulator set |
494 | /// INTERNAL ONLY |
495 | /// |
496 | #define (z, n, _) \ |
497 | template< \ |
498 | typename Feature \ |
499 | , typename AccumulatorSet \ |
500 | BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, typename A) \ |
501 | > \ |
502 | typename mpl::apply<AccumulatorSet, Feature>::type::result_type \ |
503 | ( \ |
504 | AccumulatorSet const &acc \ |
505 | BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(z, n, A, const &a) \ |
506 | , typename boost::enable_if< \ |
507 | parameter::is_argument_pack<A0> \ |
508 | , detail::_enabler \ |
509 | >::type \ |
510 | ) \ |
511 | { \ |
512 | return find_accumulator<Feature>(acc).result( \ |
513 | ( \ |
514 | boost::accumulators::accumulator = acc \ |
515 | BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \ |
516 | ) \ |
517 | ); \ |
518 | } \ |
519 | template< \ |
520 | typename Feature \ |
521 | , typename AccumulatorSet \ |
522 | BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, typename A) \ |
523 | > \ |
524 | typename mpl::apply<AccumulatorSet, Feature>::type::result_type \ |
525 | ( \ |
526 | AccumulatorSet const &acc \ |
527 | BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(z, n, A, const &a) \ |
528 | , typename boost::disable_if< \ |
529 | parameter::is_argument_pack<A0> \ |
530 | , detail::_enabler \ |
531 | >::type \ |
532 | ) \ |
533 | { \ |
534 | return find_accumulator<Feature>(acc).result(( \ |
535 | boost::accumulators::accumulator = acc \ |
536 | , boost::accumulators::sample = BOOST_PP_ENUM_PARAMS_Z(z, n, a) \ |
537 | )); \ |
538 | } |
539 | |
540 | BOOST_PP_REPEAT_FROM_TO( |
541 | 1 |
542 | , BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS) |
543 | , BOOST_ACCUMULATORS_EXTRACT_RESULT_FUN |
544 | , _ |
545 | ) |
546 | |
547 | }} // namespace boost::accumulators |
548 | |
549 | #endif |
550 | |