1 ///////////////////////////////////////////////////////////////////////////////
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)
8 #ifndef BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATOR_SET_HPP_EAN_28_10_2005
9 #define BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATOR_SET_HPP_EAN_28_10_2005
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>
41 namespace boost { namespace accumulators
46 ///////////////////////////////////////////////////////////////////////////////
47 // accumulator_visitor
48 // wrap a boost::parameter argument pack in a Fusion extractor object
49 template<typename Args>
50 struct accumulator_visitor
52 explicit accumulator_visitor(Args const &a)
57 template<typename Accumulator>
58 void operator ()(Accumulator &accumulator) const
60 accumulator(this->args);
64 accumulator_visitor &operator =(accumulator_visitor const &);
68 template<typename Args>
69 inline accumulator_visitor<Args> const make_accumulator_visitor(Args const &args)
71 return accumulator_visitor<Args>(args);
74 ///////////////////////////////////////////////////////////////////////////////
75 // accumulator_set_base
76 struct accumulator_set_base
80 ///////////////////////////////////////////////////////////////////////////////
83 struct is_accumulator_set
87 , typename boost::remove_const<
88 typename boost::remove_reference<T>::type
97 // function object that serialize an accumulator
98 template<typename Archive>
99 struct serialize_accumulator
101 serialize_accumulator(Archive & _ar, const unsigned int _file_version) :
102 ar(_ar), file_version(_file_version)
105 template<typename Accumulator>
106 void operator ()(Accumulator &accumulator)
108 accumulator.serialize(ar, file_version);
113 const unsigned int file_version;
116 } // namespace detail
119 #pragma warning(push)
120 #pragma warning(disable: 4355) // warning C4355: 'this' : used in base member initializer list
123 ///////////////////////////////////////////////////////////////////////////////
124 /// \brief A set of accumulators.
126 /// accumulator_set resolves the dependencies between features and ensures that
127 /// the accumulators in the set are updated in the proper order.
129 /// acccumulator_set provides a general mechanism to visit the accumulators
130 /// in the set in order, with or without a filter. You can also fetch a reference
131 /// to an accumulator that corresponds to a feature.
133 template<typename Sample, typename Features, typename Weight>
134 struct accumulator_set
135 : detail::accumulator_set_base
137 typedef Sample sample_type; ///< The type of the samples that will be accumulated
138 typedef Features features_type; ///< An MPL sequence of the features that should be accumulated.
139 typedef Weight weight_type; ///< The type of the weight parameter. Must be a scalar. Defaults to void.
144 typename detail::make_accumulator_tuple<
149 accumulators_mpl_vector;
151 // generate a fusion::list of accumulators
155 typename detail::meta::make_acc_list<
156 accumulators_mpl_vector
162 //BOOST_MPL_ASSERT((mpl::is_sequence<accumulators_type>));
164 ///////////////////////////////////////////////////////////////////////////////
165 /// default-construct all contained accumulators
168 detail::make_acc_list(
169 accumulators_mpl_vector()
170 , (boost::accumulators::accumulator = *this)
174 // Add-ref the Features that the user has specified
175 this->template visit_if<detail::contains_feature_of_<Features> >(
176 detail::make_add_ref_visitor(boost::accumulators::accumulator = *this)
182 /// \param a1 Optional named parameter to be passed to all the accumulators
183 template<typename A1>
184 explicit accumulator_set(
186 , typename boost::enable_if<
187 parameter::is_argument_pack<A1>
189 >::type = detail::_enabler()
191 detail::make_acc_list(
192 accumulators_mpl_vector()
193 , (boost::accumulators::accumulator = *this, a1)
197 // Add-ref the Features that the user has specified
198 this->template visit_if<detail::contains_feature_of_<Features> >(
199 detail::make_add_ref_visitor(boost::accumulators::accumulator = *this)
205 /// \param a1 Optional sample parameter to be passed to all the accumulators
206 template<typename A1>
207 explicit accumulator_set(
209 , typename boost::disable_if<
210 parameter::is_argument_pack<A1>
212 >::type = detail::_enabler()
214 detail::make_acc_list(
215 accumulators_mpl_vector()
217 boost::accumulators::accumulator = *this
218 , boost::accumulators::sample = a1
223 // Add-ref the Features that the user has specified
224 this->template visit_if<detail::contains_feature_of_<Features> >(
225 detail::make_add_ref_visitor(boost::accumulators::accumulator = *this)
229 // ... other overloads generated by Boost.Preprocessor:
233 #define BOOST_ACCUMULATORS_ACCUMULATOR_SET_CTOR(z, n, _) \
234 template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
236 BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a) \
237 , typename boost::enable_if< \
238 parameter::is_argument_pack<A0> \
240 >::type = detail::_enabler() \
242 detail::make_acc_list( \
243 accumulators_mpl_vector() \
245 boost::accumulators::accumulator = *this \
246 BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \
251 /* Add-ref the Features that the user has specified */ \
252 this->template visit_if<detail::contains_feature_of_<Features> >( \
253 detail::make_add_ref_visitor(boost::accumulators::accumulator = *this) \
256 template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
258 BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a) \
259 , typename boost::disable_if< \
260 parameter::is_argument_pack<A0> \
262 >::type = detail::_enabler() \
264 detail::make_acc_list( \
265 accumulators_mpl_vector() \
267 boost::accumulators::accumulator = *this \
268 , boost::accumulators::sample = BOOST_PP_ENUM_PARAMS_Z(z, n, a) \
273 /* Add-ref the Features that the user has specified */ \
274 this->template visit_if<detail::contains_feature_of_<Features> >( \
275 detail::make_add_ref_visitor(boost::accumulators::accumulator = *this) \
281 BOOST_PP_REPEAT_FROM_TO(
283 , BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
284 , BOOST_ACCUMULATORS_ACCUMULATOR_SET_CTOR
288 #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
291 template<typename A1, typename A2, ...>
292 accumulator_set(A1 const &a1, A2 const &a2, ...);
295 // ... other overloads generated by Boost.Preprocessor below ...
297 ///////////////////////////////////////////////////////////////////////////////
299 /// \param func UnaryFunction which is invoked with each accumulator in turn.
300 template<typename UnaryFunction>
301 void visit(UnaryFunction const &func)
303 fusion::for_each(this->accumulators, func);
306 ///////////////////////////////////////////////////////////////////////////////
307 /// Conditional visitation
308 /// \param func UnaryFunction which is invoked with each accumulator in turn,
309 /// provided the accumulator satisfies the MPL predicate FilterPred.
310 template<typename FilterPred, typename UnaryFunction>
311 void visit_if(UnaryFunction const &func)
313 fusion::filter_view<accumulators_type, FilterPred> filtered_accs(this->accumulators);
314 fusion::for_each(filtered_accs, func);
317 ///////////////////////////////////////////////////////////////////////////////
318 /// The return type of the operator() overloads is void.
319 typedef void result_type;
321 ///////////////////////////////////////////////////////////////////////////////
323 /// \param a1 Optional named parameter to be passed to all the accumulators
327 detail::make_accumulator_visitor(
328 boost::accumulators::accumulator = *this
333 // ... other overloads generated by Boost.Preprocessor:
337 #define BOOST_ACCUMULATORS_ACCUMULATOR_SET_FUN_OP(z, n, _) \
338 template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
340 BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a) \
341 , typename boost::enable_if< \
342 parameter::is_argument_pack<A0> \
344 >::type = detail::_enabler() \
348 detail::make_accumulator_visitor( \
350 boost::accumulators::accumulator = *this \
351 BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \
356 template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
358 BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a) \
359 , typename boost::disable_if< \
360 parameter::is_argument_pack<A0> \
362 >::type = detail::_enabler() \
366 detail::make_accumulator_visitor( \
368 boost::accumulators::accumulator = *this \
369 , boost::accumulators::sample = BOOST_PP_ENUM_PARAMS_Z(z, n, a) \
377 BOOST_PP_REPEAT_FROM_TO(
379 , BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
380 , BOOST_ACCUMULATORS_ACCUMULATOR_SET_FUN_OP
384 #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
387 template<typename A1, typename A2, ...>
388 void operator ()(A1 const &a1, A2 const &a2, ...);
391 ///////////////////////////////////////////////////////////////////////////////
393 template<typename Feature>
395 : fusion::result_of::value_of<
396 typename fusion::result_of::find_if<
398 , detail::matches_feature<Feature>
404 ///////////////////////////////////////////////////////////////////////////////
406 template<typename Feature>
407 typename apply<Feature>::type &extract()
409 return *fusion::find_if<detail::matches_feature<Feature> >(this->accumulators);
413 template<typename Feature>
414 typename apply<Feature>::type const &extract() const
416 return *fusion::find_if<detail::matches_feature<Feature> >(this->accumulators);
419 ///////////////////////////////////////////////////////////////////////////////
421 template<typename Feature>
424 // You can only drop the features that you have specified explicitly
425 typedef typename apply<Feature>::type the_accumulator;
426 BOOST_MPL_ASSERT((detail::contains_feature_of<Features, the_accumulator>));
429 typename feature_of<typename as_feature<Feature>::type>::type
432 (*fusion::find_if<detail::matches_feature<Feature> >(this->accumulators))
433 .drop(boost::accumulators::accumulator = *this);
435 // Also drop accumulators that this feature depends on
436 typedef typename the_feature::dependencies dependencies;
437 this->template visit_if<detail::contains_feature_of_<dependencies> >(
438 detail::make_drop_visitor(boost::accumulators::accumulator = *this)
442 // make the accumulator set serializeable
443 template<class Archive>
444 void serialize(Archive & ar, const unsigned int file_version)
446 detail::serialize_accumulator<Archive> serializer(ar, file_version);
447 fusion::for_each(this->accumulators, serializer);
452 accumulators_type accumulators;
459 ///////////////////////////////////////////////////////////////////////////////
461 // find an accumulator in an accumulator_set corresponding to a feature
462 template<typename Feature, typename AccumulatorSet>
463 typename mpl::apply<AccumulatorSet, Feature>::type &
464 find_accumulator(AccumulatorSet &acc BOOST_ACCUMULATORS_PROTO_DISABLE_IF_IS_CONST(AccumulatorSet))
466 return acc.template extract<Feature>();
470 template<typename Feature, typename AccumulatorSet>
471 typename mpl::apply<AccumulatorSet, Feature>::type const &
472 find_accumulator(AccumulatorSet const &acc)
474 return acc.template extract<Feature>();
477 template<typename Feature, typename AccumulatorSet>
478 typename mpl::apply<AccumulatorSet, Feature>::type::result_type
479 extract_result(AccumulatorSet const &acc)
481 return find_accumulator<Feature>(acc).result(
482 boost::accumulators::accumulator = acc
486 ///////////////////////////////////////////////////////////////////////////////
488 // extract a result from an accumulator set
491 #define BOOST_ACCUMULATORS_EXTRACT_RESULT_FUN(z, n, _) \
494 , typename AccumulatorSet \
495 BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, typename A) \
497 typename mpl::apply<AccumulatorSet, Feature>::type::result_type \
499 AccumulatorSet const &acc \
500 BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(z, n, A, const &a) \
501 , typename boost::enable_if< \
502 parameter::is_argument_pack<A0> \
507 return find_accumulator<Feature>(acc).result( \
509 boost::accumulators::accumulator = acc \
510 BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \
516 , typename AccumulatorSet \
517 BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, typename A) \
519 typename mpl::apply<AccumulatorSet, Feature>::type::result_type \
521 AccumulatorSet const &acc \
522 BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(z, n, A, const &a) \
523 , typename boost::disable_if< \
524 parameter::is_argument_pack<A0> \
529 return find_accumulator<Feature>(acc).result(( \
530 boost::accumulators::accumulator = acc \
531 , boost::accumulators::sample = BOOST_PP_ENUM_PARAMS_Z(z, n, a) \
535 BOOST_PP_REPEAT_FROM_TO(
537 , BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
538 , BOOST_ACCUMULATORS_EXTRACT_RESULT_FUN
542 }} // namespace boost::accumulators