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/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>
34 namespace boost { namespace accumulators
39 ///////////////////////////////////////////////////////////////////////////////
40 // accumulator_visitor
41 // wrap a boost::parameter argument pack in a Fusion extractor object
42 template<typename Args>
43 struct accumulator_visitor
45 explicit accumulator_visitor(Args const &a)
50 template<typename Accumulator>
51 void operator ()(Accumulator &accumulator) const
53 accumulator(this->args);
57 accumulator_visitor &operator =(accumulator_visitor const &);
61 template<typename Args>
62 inline accumulator_visitor<Args> const make_accumulator_visitor(Args const &args)
64 return accumulator_visitor<Args>(args);
68 parameter::parameters<
69 parameter::required<tag::accumulator>
70 , parameter::optional<tag::sample>
71 // ... and others which are not specified here...
75 ///////////////////////////////////////////////////////////////////////////////
76 // accumulator_set_base
77 struct accumulator_set_base
81 ///////////////////////////////////////////////////////////////////////////////
84 struct is_accumulator_set
85 : is_base_and_derived<accumulator_set_base, T>
93 #pragma warning(disable: 4355) // warning C4355: 'this' : used in base member initializer list
96 ///////////////////////////////////////////////////////////////////////////////
97 /// \brief A set of accumulators.
99 /// accumulator_set resolves the dependencies between features and ensures that
100 /// the accumulators in the set are updated in the proper order.
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.
106 template<typename Sample, typename Features, typename Weight>
107 struct accumulator_set
108 : detail::accumulator_set_base
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.
117 typename detail::make_accumulator_tuple<
122 accumulators_mpl_vector;
124 // generate a fusion::list of accumulators
128 typename detail::meta::make_acc_list<
129 accumulators_mpl_vector
135 //BOOST_MPL_ASSERT((mpl::is_sequence<accumulators_type>));
137 ///////////////////////////////////////////////////////////////////////////////
138 /// default-construct all contained accumulators
141 detail::make_acc_list(
142 accumulators_mpl_vector()
143 , detail::accumulator_params()(*this)
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))
155 /// \param a1 Optional named parameter to be passed to all the accumulators
156 template<typename A1>
157 explicit accumulator_set(A1 const &a1)
159 detail::make_acc_list(
160 accumulators_mpl_vector()
161 , detail::accumulator_params()(*this, a1)
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))
171 // ... other overloads generated by Boost.Preprocessor:
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)) \
179 detail::make_acc_list( \
180 accumulators_mpl_vector() \
181 , detail::accumulator_params()( \
182 *this BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \
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)) \
195 BOOST_PP_REPEAT_FROM_TO(
197 , BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
198 , BOOST_ACCUMULATORS_ACCUMULATOR_SET_CTOR
202 #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
205 template<typename A1, typename A2, ...>
206 accumulator_set(A1 const &a1, A2 const &a2, ...);
209 // ... other overloads generated by Boost.Preprocessor below ...
211 ///////////////////////////////////////////////////////////////////////////////
213 /// \param func UnaryFunction which is invoked with each accumulator in turn.
214 template<typename UnaryFunction>
215 void visit(UnaryFunction const &func)
217 fusion::for_each(this->accumulators, func);
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)
227 fusion::filter_view<accumulators_type, FilterPred> filtered_accs(this->accumulators);
228 fusion::for_each(filtered_accs, func);
231 ///////////////////////////////////////////////////////////////////////////////
232 /// The return type of the operator() overloads is void.
233 typedef void result_type;
235 ///////////////////////////////////////////////////////////////////////////////
237 /// \param a1 Optional named parameter to be passed to all the accumulators
241 detail::make_accumulator_visitor(
242 detail::accumulator_params()(*this)
247 template<typename A1>
248 void operator ()(A1 const &a1)
251 detail::make_accumulator_visitor(
252 detail::accumulator_params()(*this, a1)
257 // ... other overloads generated by Boost.Preprocessor:
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)) \
266 detail::make_accumulator_visitor( \
267 detail::accumulator_params()( \
268 *this BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \
276 BOOST_PP_REPEAT_FROM_TO(
278 , BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
279 , BOOST_ACCUMULATORS_ACCUMULATOR_SET_FUN_OP
283 #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
286 template<typename A1, typename A2, ...>
287 void operator ()(A1 const &a1, A2 const &a2, ...);
290 ///////////////////////////////////////////////////////////////////////////////
292 template<typename Feature>
294 : fusion::result_of::value_of<
295 typename fusion::result_of::find_if<
297 , detail::matches_feature<Feature>
303 ///////////////////////////////////////////////////////////////////////////////
305 template<typename Feature>
306 typename apply<Feature>::type &extract()
308 return *fusion::find_if<detail::matches_feature<Feature> >(this->accumulators);
312 template<typename Feature>
313 typename apply<Feature>::type const &extract() const
315 return *fusion::find_if<detail::matches_feature<Feature> >(this->accumulators);
318 ///////////////////////////////////////////////////////////////////////////////
320 template<typename Feature>
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>));
328 typename feature_of<typename as_feature<Feature>::type>::type
331 (*fusion::find_if<detail::matches_feature<Feature> >(this->accumulators))
332 .drop(detail::accumulator_params()(*this));
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))
343 accumulators_type accumulators;
350 ///////////////////////////////////////////////////////////////////////////////
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))
357 return acc.template extract<Feature>();
361 template<typename Feature, typename AccumulatorSet>
362 typename mpl::apply<AccumulatorSet, Feature>::type const &
363 find_accumulator(AccumulatorSet const &acc)
365 return acc.template extract<Feature>();
368 ///////////////////////////////////////////////////////////////////////////////
370 // extract a result from an accumulator set
373 #define BOOST_ACCUMULATORS_EXTRACT_RESULT_FUN(z, n, _) \
376 , typename AccumulatorSet \
377 BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, typename A) \
379 typename mpl::apply<AccumulatorSet, Feature>::type::result_type \
381 AccumulatorSet const &acc \
382 BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(z, n, A, const &a) \
385 return find_accumulator<Feature>(acc).result( \
386 detail::accumulator_params()( \
388 BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \
394 BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
395 , BOOST_ACCUMULATORS_EXTRACT_RESULT_FUN
399 }} // namespace boost::accumulators