boost/accumulators/framework/accumulator_set.hpp
/////////////////////////////////////////////////////////////////////////////// // accumulator_set.hpp // // Copyright 2005 Eric Niebler. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATOR_SET_HPP_EAN_28_10_2005 #define BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATOR_SET_HPP_EAN_28_10_2005 #include <boost/version.hpp> #include <boost/mpl/apply.hpp> #include <boost/mpl/assert.hpp> #include <boost/mpl/protect.hpp> #include <boost/mpl/identity.hpp> #include <boost/mpl/is_sequence.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/type_traits/is_base_and_derived.hpp> #include <boost/parameter/parameters.hpp> #include <boost/preprocessor/repetition/repeat_from_to.hpp> #include <boost/preprocessor/repetition/enum_binary_params.hpp> #include <boost/accumulators/accumulators_fwd.hpp> #include <boost/accumulators/framework/depends_on.hpp> #include <boost/accumulators/framework/accumulator_concept.hpp> #include <boost/accumulators/framework/parameters/accumulator.hpp> #include <boost/accumulators/framework/parameters/sample.hpp> #include <boost/accumulators/framework/accumulators/external_accumulator.hpp> #include <boost/accumulators/framework/accumulators/droppable_accumulator.hpp> #include <boost/fusion/include/any.hpp> #include <boost/fusion/include/find_if.hpp> #include <boost/fusion/include/for_each.hpp> #include <boost/fusion/include/filter_view.hpp> namespace boost { namespace accumulators { namespace detail { /////////////////////////////////////////////////////////////////////////////// // accumulator_visitor // wrap a boost::parameter argument pack in a Fusion extractor object template<typename Args> struct accumulator_visitor { explicit accumulator_visitor(Args const &a) : args(a) { } template<typename Accumulator> void operator ()(Accumulator &accumulator) const { accumulator(this->args); } private: accumulator_visitor &operator =(accumulator_visitor const &); Args const &args; }; template<typename Args> inline accumulator_visitor<Args> const make_accumulator_visitor(Args const &args) { return accumulator_visitor<Args>(args); } typedef parameter::parameters< parameter::required<tag::accumulator> , parameter::optional<tag::sample> // ... and others which are not specified here... > accumulator_params; /////////////////////////////////////////////////////////////////////////////// // accumulator_set_base struct accumulator_set_base { }; /////////////////////////////////////////////////////////////////////////////// // is_accumulator_set template<typename T> struct is_accumulator_set : is_base_and_derived<accumulator_set_base, T> { }; } // namespace detail #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4355) // warning C4355: 'this' : used in base member initializer list #endif /////////////////////////////////////////////////////////////////////////////// /// \brief A set of accumulators. /// /// accumulator_set resolves the dependencies between features and ensures that /// the accumulators in the set are updated in the proper order. /// /// acccumulator_set provides a general mechanism to visit the accumulators /// in the set in order, with or without a filter. You can also fetch a reference /// to an accumulator that corresponds to a feature. /// template<typename Sample, typename Features, typename Weight> struct accumulator_set : detail::accumulator_set_base { typedef Sample sample_type; ///< The type of the samples that will be accumulated typedef Features features_type; ///< An MPL sequence of the features that should be accumulated. typedef Weight weight_type; ///< The type of the weight parameter. Must be a scalar. Defaults to void. /// INTERNAL ONLY /// typedef typename detail::make_accumulator_tuple< Features , Sample , Weight >::type accumulators_mpl_vector; // generate a fusion::list of accumulators /// INTERNAL ONLY /// typedef typename detail::meta::make_acc_list< accumulators_mpl_vector >::type accumulators_type; /// INTERNAL ONLY /// //BOOST_MPL_ASSERT((mpl::is_sequence<accumulators_type>)); /////////////////////////////////////////////////////////////////////////////// /// default-construct all contained accumulators accumulator_set() : accumulators( detail::make_acc_list( accumulators_mpl_vector() , detail::accumulator_params()(*this) ) ) { // Add-ref the Features that the user has specified this->template visit_if<detail::contains_feature_of_<Features> >( detail::make_add_ref_visitor(detail::accumulator_params()(*this)) ); } /// \overload /// /// \param a1 Optional named parameter to be passed to all the accumulators template<typename A1> explicit accumulator_set(A1 const &a1) : accumulators( detail::make_acc_list( accumulators_mpl_vector() , detail::accumulator_params()(*this, a1) ) ) { // Add-ref the Features that the user has specified this->template visit_if<detail::contains_feature_of_<Features> >( detail::make_add_ref_visitor(detail::accumulator_params()(*this)) ); } // ... other overloads generated by Boost.Preprocessor: /// INTERNAL ONLY /// #define BOOST_ACCUMULATORS_ACCUMULATOR_SET_CTOR(z, n, _) \ template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ accumulator_set(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a)) \ : accumulators( \ detail::make_acc_list( \ accumulators_mpl_vector() \ , detail::accumulator_params()( \ *this BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \ ) \ ) \ ) \ { \ /* Add-ref the Features that the user has specified */ \ this->template visit_if<detail::contains_feature_of_<Features> >( \ detail::make_add_ref_visitor(detail::accumulator_params()(*this)) \ ); \ } /// INTERNAL ONLY /// BOOST_PP_REPEAT_FROM_TO( 2 , BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS) , BOOST_ACCUMULATORS_ACCUMULATOR_SET_CTOR , _ ) #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED /// \overload /// template<typename A1, typename A2, ...> accumulator_set(A1 const &a1, A2 const &a2, ...); #endif // ... other overloads generated by Boost.Preprocessor below ... /////////////////////////////////////////////////////////////////////////////// /// Visitation /// \param func UnaryFunction which is invoked with each accumulator in turn. template<typename UnaryFunction> void visit(UnaryFunction const &func) { fusion::for_each(this->accumulators, func); } /////////////////////////////////////////////////////////////////////////////// /// Conditional visitation /// \param func UnaryFunction which is invoked with each accumulator in turn, /// provided the accumulator satisfies the MPL predicate FilterPred. template<typename FilterPred, typename UnaryFunction> void visit_if(UnaryFunction const &func) { fusion::filter_view<accumulators_type, FilterPred> filtered_accs(this->accumulators); fusion::for_each(filtered_accs, func); } /////////////////////////////////////////////////////////////////////////////// /// The return type of the operator() overloads is void. typedef void result_type; /////////////////////////////////////////////////////////////////////////////// /// Accumulation /// \param a1 Optional named parameter to be passed to all the accumulators void operator ()() { this->visit( detail::make_accumulator_visitor( detail::accumulator_params()(*this) ) ); } template<typename A1> void operator ()(A1 const &a1) { this->visit( detail::make_accumulator_visitor( detail::accumulator_params()(*this, a1) ) ); } // ... other overloads generated by Boost.Preprocessor: /// INTERNAL ONLY /// #define BOOST_ACCUMULATORS_ACCUMULATOR_SET_FUN_OP(z, n, _) \ template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \ void operator ()(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a)) \ { \ this->visit( \ detail::make_accumulator_visitor( \ detail::accumulator_params()( \ *this BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \ ) \ ) \ ); \ } /// INTERNAL ONLY /// BOOST_PP_REPEAT_FROM_TO( 2 , BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS) , BOOST_ACCUMULATORS_ACCUMULATOR_SET_FUN_OP , _ ) #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED /// \overload /// template<typename A1, typename A2, ...> void operator ()(A1 const &a1, A2 const &a2, ...); #endif /////////////////////////////////////////////////////////////////////////////// /// Extraction template<typename Feature> struct apply : fusion::result_of::value_of< typename fusion::result_of::find_if< accumulators_type , detail::matches_feature<Feature> >::type > { }; /////////////////////////////////////////////////////////////////////////////// /// Extraction template<typename Feature> typename apply<Feature>::type &extract() { return *fusion::find_if<detail::matches_feature<Feature> >(this->accumulators); } /// \overload template<typename Feature> typename apply<Feature>::type const &extract() const { return *fusion::find_if<detail::matches_feature<Feature> >(this->accumulators); } /////////////////////////////////////////////////////////////////////////////// /// Drop template<typename Feature> void drop() { // You can only drop the features that you have specified explicitly typedef typename apply<Feature>::type the_accumulator; BOOST_MPL_ASSERT((detail::contains_feature_of<Features, the_accumulator>)); typedef typename feature_of<typename as_feature<Feature>::type>::type the_feature; (*fusion::find_if<detail::matches_feature<Feature> >(this->accumulators)) .drop(detail::accumulator_params()(*this)); // Also drop accumulators that this feature depends on typedef typename the_feature::dependencies dependencies; this->template visit_if<detail::contains_feature_of_<dependencies> >( detail::make_drop_visitor(detail::accumulator_params()(*this)) ); } private: accumulators_type accumulators; }; #ifdef _MSC_VER #pragma warning(pop) #endif /////////////////////////////////////////////////////////////////////////////// // find_accumulator // find an accumulator in an accumulator_set corresponding to a feature template<typename Feature, typename AccumulatorSet> typename mpl::apply<AccumulatorSet, Feature>::type & find_accumulator(AccumulatorSet &acc BOOST_ACCUMULATORS_PROTO_DISABLE_IF_IS_CONST(AccumulatorSet)) { return acc.template extract<Feature>(); } /// \overload template<typename Feature, typename AccumulatorSet> typename mpl::apply<AccumulatorSet, Feature>::type const & find_accumulator(AccumulatorSet const &acc) { return acc.template extract<Feature>(); } /////////////////////////////////////////////////////////////////////////////// // extract_result // extract a result from an accumulator set /// INTERNAL ONLY /// #define BOOST_ACCUMULATORS_EXTRACT_RESULT_FUN(z, n, _) \ template< \ typename Feature \ , typename AccumulatorSet \ BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, typename A) \ > \ typename mpl::apply<AccumulatorSet, Feature>::type::result_type \ extract_result( \ AccumulatorSet const &acc \ BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(z, n, A, const &a) \ ) \ { \ return find_accumulator<Feature>(acc).result( \ detail::accumulator_params()( \ acc \ BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \ ) \ ); \ } BOOST_PP_REPEAT( BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS) , BOOST_ACCUMULATORS_EXTRACT_RESULT_FUN , _ ) }} // namespace boost::accumulators #endif





