/////////////////////////////////////////////////////////////////////////////// // 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace accumulators { namespace detail { /////////////////////////////////////////////////////////////////////////////// // accumulator_visitor // wrap a boost::parameter argument pack in a Fusion extractor object template struct accumulator_visitor { explicit accumulator_visitor(Args const &a) : args(a) { } template void operator ()(Accumulator &accumulator) const { accumulator(this->args); } private: accumulator_visitor &operator =(accumulator_visitor const &); Args const &args; }; template inline accumulator_visitor const make_accumulator_visitor(Args const &args) { return accumulator_visitor(args); } typedef parameter::parameters< parameter::required , parameter::optional // ... and others which are not specified here... > accumulator_params; /////////////////////////////////////////////////////////////////////////////// // accumulator_set_base struct accumulator_set_base { }; /////////////////////////////////////////////////////////////////////////////// // is_accumulator_set template struct is_accumulator_set : is_base_and_derived { }; } // 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 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)); /////////////////////////////////////////////////////////////////////////////// /// 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::make_add_ref_visitor(detail::accumulator_params()(*this)) ); } /// \overload /// /// \param a1 Optional named parameter to be passed to all the accumulators template 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::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 \ 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::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 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 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 void visit_if(UnaryFunction const &func) { fusion::filter_view 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 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 \ 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 void operator ()(A1 const &a1, A2 const &a2, ...); #endif /////////////////////////////////////////////////////////////////////////////// /// Extraction template struct apply : fusion::result_of::value_of< typename fusion::result_of::find_if< accumulators_type , detail::matches_feature >::type > { }; /////////////////////////////////////////////////////////////////////////////// /// Extraction template typename apply::type &extract() { return *fusion::find_if >(this->accumulators); } /// \overload template typename apply::type const &extract() const { return *fusion::find_if >(this->accumulators); } /////////////////////////////////////////////////////////////////////////////// /// Drop template void drop() { // You can only drop the features that you have specified explicitly typedef typename apply::type the_accumulator; BOOST_MPL_ASSERT((detail::contains_feature_of)); typedef typename feature_of::type>::type the_feature; (*fusion::find_if >(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::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 mpl::apply::type & find_accumulator(AccumulatorSet &acc BOOST_ACCUMULATORS_PROTO_DISABLE_IF_IS_CONST(AccumulatorSet)) { return acc.template extract(); } /// \overload template typename mpl::apply::type const & find_accumulator(AccumulatorSet const &acc) { return acc.template extract(); } /////////////////////////////////////////////////////////////////////////////// // 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::type::result_type \ extract_result( \ AccumulatorSet const &acc \ BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(z, n, A, const &a) \ ) \ { \ return find_accumulator(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