| /////////////////////////////////////////////////////////////////////////////// |
| // depends_on.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_DEPENDS_ON_HPP_EAN_28_10_2005 |
| #define BOOST_ACCUMULATORS_FRAMEWORK_DEPENDS_ON_HPP_EAN_28_10_2005 |
| |
| #include <boost/version.hpp> |
| #include <boost/mpl/end.hpp> |
| #include <boost/mpl/map.hpp> |
| #include <boost/mpl/fold.hpp> |
| #include <boost/mpl/size.hpp> |
| #include <boost/mpl/sort.hpp> |
| #include <boost/mpl/insert.hpp> |
| #include <boost/mpl/assert.hpp> |
| #include <boost/mpl/remove.hpp> |
| #include <boost/mpl/vector.hpp> |
| #include <boost/mpl/inherit.hpp> |
| #include <boost/mpl/identity.hpp> |
| #include <boost/mpl/equal_to.hpp> |
| #include <boost/mpl/contains.hpp> |
| #include <boost/mpl/transform.hpp> |
| #include <boost/mpl/is_sequence.hpp> |
| #include <boost/mpl/placeholders.hpp> |
| #include <boost/mpl/insert_range.hpp> |
| #include <boost/mpl/transform_view.hpp> |
| #include <boost/mpl/inherit_linearly.hpp> |
| #include <boost/type_traits/is_base_and_derived.hpp> |
| #include <boost/preprocessor/repetition/repeat.hpp> |
| #include <boost/preprocessor/repetition/enum_params.hpp> |
| #include <boost/preprocessor/facilities/intercept.hpp> |
| #include <boost/accumulators/accumulators_fwd.hpp> |
| #include <boost/fusion/include/next.hpp> |
| #include <boost/fusion/include/equal_to.hpp> |
| #include <boost/fusion/include/value_of.hpp> |
| #include <boost/fusion/include/mpl.hpp> |
| #include <boost/fusion/include/end.hpp> |
| #include <boost/fusion/include/begin.hpp> |
| #include <boost/fusion/include/cons.hpp> |
| |
| namespace boost { namespace accumulators |
| { |
| /////////////////////////////////////////////////////////////////////////// |
| // as_feature |
| template<typename Feature> |
| struct as_feature |
| { |
| typedef Feature type; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // weighted_feature |
| template<typename Feature> |
| struct as_weighted_feature |
| { |
| typedef Feature type; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // feature_of |
| template<typename Feature> |
| struct feature_of |
| { |
| typedef Feature type; |
| }; |
| |
| namespace detail |
| { |
| /////////////////////////////////////////////////////////////////////////// |
| // feature_tag |
| template<typename Accumulator> |
| struct feature_tag |
| { |
| typedef typename Accumulator::feature_tag type; |
| }; |
| |
| template<typename Feature> |
| struct undroppable |
| { |
| typedef Feature type; |
| }; |
| |
| template<typename Feature> |
| struct undroppable<tag::droppable<Feature> > |
| { |
| typedef Feature type; |
| }; |
| |
| // For the purpose of determining whether one feature depends on another, |
| // disregard whether the feature is droppable or not. |
| template<typename A, typename B> |
| struct is_dependent_on |
| : is_base_and_derived< |
| typename undroppable<B>::type |
| , typename undroppable<A>::type |
| > |
| {}; |
| |
| template<typename Features> |
| struct depends_on_base |
| : mpl::inherit_linearly< |
| typename mpl::sort<Features, is_dependent_on<mpl::_1, mpl::_2> >::type |
| // Don't inherit multiply from a feature |
| , mpl::if_< |
| is_dependent_on<mpl::_1, mpl::_2> |
| , mpl::_1 |
| , mpl::inherit<mpl::_1, mpl::_2> |
| > |
| >::type |
| { |
| }; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////// |
| /// depends_on |
| template<BOOST_PP_ENUM_PARAMS(BOOST_ACCUMULATORS_MAX_FEATURES, typename Feature)> |
| struct depends_on |
| : detail::depends_on_base< |
| typename mpl::transform< |
| mpl::vector<BOOST_PP_ENUM_PARAMS(BOOST_ACCUMULATORS_MAX_FEATURES, Feature)> |
| , as_feature<mpl::_1> |
| >::type |
| > |
| { |
| typedef mpl::false_ is_weight_accumulator; |
| typedef |
| typename mpl::transform< |
| mpl::vector<BOOST_PP_ENUM_PARAMS(BOOST_ACCUMULATORS_MAX_FEATURES, Feature)> |
| , as_feature<mpl::_1> |
| >::type |
| dependencies; |
| }; |
| |
| namespace detail |
| { |
| template<typename Feature> |
| struct matches_feature |
| { |
| template<typename Accumulator> |
| struct apply |
| : is_same< |
| typename feature_of<typename as_feature<Feature>::type>::type |
| , typename feature_of<typename as_feature<typename feature_tag<Accumulator>::type>::type>::type |
| > |
| {}; |
| }; |
| |
| template<typename Features, typename Accumulator> |
| struct contains_feature_of |
| { |
| typedef |
| mpl::transform_view<Features, feature_of<as_feature<mpl::_> > > |
| features_list; |
| |
| typedef |
| typename feature_of<typename feature_tag<Accumulator>::type>::type |
| the_feature; |
| |
| typedef |
| typename mpl::contains<features_list, the_feature>::type |
| type; |
| }; |
| |
| // This is to work around a bug in early versions of Fusion which caused |
| // a compile error if contains_feature_of<List, mpl::_> is used as a |
| // predicate to fusion::find_if |
| template<typename Features> |
| struct contains_feature_of_ |
| { |
| template<typename Accumulator> |
| struct apply |
| : contains_feature_of<Features, Accumulator> |
| {}; |
| }; |
| |
| template< |
| typename First |
| , typename Last |
| , bool is_empty = fusion::result_of::equal_to<First, Last>::value |
| > |
| struct build_acc_list; |
| |
| template<typename First, typename Last> |
| struct build_acc_list<First, Last, true> |
| { |
| typedef fusion::nil type; |
| |
| template<typename Args> |
| static fusion::nil |
| call(Args const &, First const&, Last const&) |
| { |
| return fusion::nil(); |
| } |
| }; |
| |
| template<typename First, typename Last> |
| struct build_acc_list<First, Last, false> |
| { |
| typedef |
| build_acc_list<typename fusion::result_of::next<First>::type, Last> |
| next_build_acc_list; |
| |
| typedef fusion::cons< |
| typename fusion::result_of::value_of<First>::type |
| , typename next_build_acc_list::type> |
| type; |
| |
| template<typename Args> |
| static type |
| call(Args const &args, First const& f, Last const& l) |
| { |
| return type(args, next_build_acc_list::call(args, fusion::next(f), l)); |
| } |
| }; |
| |
| namespace meta |
| { |
| template<typename Sequence> |
| struct make_acc_list |
| : build_acc_list< |
| typename fusion::result_of::begin<Sequence>::type |
| , typename fusion::result_of::end<Sequence>::type |
| > |
| {}; |
| } |
| |
| template<typename Sequence, typename Args> |
| typename meta::make_acc_list<Sequence>::type |
| make_acc_list(Sequence const &seq, Args const &args) |
| { |
| return meta::make_acc_list<Sequence>::call(args, fusion::begin(seq), fusion::end(seq)); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // checked_as_weighted_feature |
| template<typename Feature> |
| struct checked_as_weighted_feature |
| { |
| typedef typename as_feature<Feature>::type feature_type; |
| typedef typename as_weighted_feature<feature_type>::type type; |
| // weighted and non-weighted flavors should provide the same feature. |
| BOOST_MPL_ASSERT(( |
| is_same< |
| typename feature_of<feature_type>::type |
| , typename feature_of<type>::type |
| > |
| )); |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // as_feature_list |
| template<typename Features, typename Weight> |
| struct as_feature_list |
| : mpl::transform_view<Features, checked_as_weighted_feature<mpl::_1> > |
| { |
| }; |
| |
| template<typename Features> |
| struct as_feature_list<Features, void> |
| : mpl::transform_view<Features, as_feature<mpl::_1> > |
| { |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // accumulator_wrapper |
| template<typename Accumulator, typename Feature> |
| struct accumulator_wrapper |
| : Accumulator |
| { |
| typedef Feature feature_tag; |
| |
| accumulator_wrapper(accumulator_wrapper const &that) |
| : Accumulator(*static_cast<Accumulator const *>(&that)) |
| { |
| } |
| |
| template<typename Args> |
| accumulator_wrapper(Args const &args) |
| : Accumulator(args) |
| { |
| } |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // to_accumulator |
| template<typename Feature, typename Sample, typename Weight> |
| struct to_accumulator |
| { |
| typedef |
| accumulator_wrapper< |
| typename mpl::apply2<typename Feature::impl, Sample, Weight>::type |
| , Feature |
| > |
| type; |
| }; |
| |
| template<typename Feature, typename Sample, typename Weight, typename Tag, typename AccumulatorSet> |
| struct to_accumulator<Feature, Sample, tag::external<Weight, Tag, AccumulatorSet> > |
| { |
| BOOST_MPL_ASSERT((is_same<Tag, void>)); |
| BOOST_MPL_ASSERT((is_same<AccumulatorSet, void>)); |
| |
| typedef |
| accumulator_wrapper< |
| typename mpl::apply2<typename Feature::impl, Sample, Weight>::type |
| , Feature |
| > |
| accumulator_type; |
| |
| typedef |
| typename mpl::if_< |
| typename Feature::is_weight_accumulator |
| , accumulator_wrapper<impl::external_impl<accumulator_type, tag::weights>, Feature> |
| , accumulator_type |
| >::type |
| type; |
| }; |
| |
| // BUGBUG work around a MPL bug wrt map insertion |
| template<typename FeatureMap, typename Feature> |
| struct insert_feature |
| : mpl::eval_if< |
| mpl::has_key<FeatureMap, typename feature_of<Feature>::type> |
| , mpl::identity<FeatureMap> |
| , mpl::insert<FeatureMap, mpl::pair<typename feature_of<Feature>::type, Feature> > |
| > |
| { |
| }; |
| |
| template<typename FeatureMap, typename Feature, typename Weight> |
| struct insert_dependencies |
| : mpl::fold< |
| as_feature_list<typename Feature::dependencies, Weight> |
| , FeatureMap |
| , insert_dependencies< |
| insert_feature<mpl::_1, mpl::_2> |
| , mpl::_2 |
| , Weight |
| > |
| > |
| { |
| }; |
| |
| template<typename FeatureMap, typename Features, typename Weight> |
| struct insert_sequence |
| : mpl::fold< // BUGBUG should use insert_range, but doesn't seem to work for maps |
| as_feature_list<Features, Weight> |
| , FeatureMap |
| , insert_feature<mpl::_1, mpl::_2> |
| > |
| { |
| }; |
| |
| template<typename Features, typename Sample, typename Weight> |
| struct make_accumulator_tuple |
| { |
| typedef |
| typename mpl::fold< |
| as_feature_list<Features, Weight> |
| , mpl::map0<> |
| , mpl::if_< |
| mpl::is_sequence<mpl::_2> |
| , insert_sequence<mpl::_1, mpl::_2, Weight> |
| , insert_feature<mpl::_1, mpl::_2> |
| > |
| >::type |
| feature_map; |
| |
| // for each element in the map, add its dependencies also |
| typedef |
| typename mpl::fold< |
| feature_map |
| , feature_map |
| , insert_dependencies<mpl::_1, mpl::second<mpl::_2>, Weight> |
| >::type |
| feature_map_with_dependencies; |
| |
| // turn the map into a vector so we can sort it |
| typedef |
| typename mpl::insert_range< |
| mpl::vector<> |
| , mpl::end<mpl::vector<> >::type |
| , mpl::transform_view<feature_map_with_dependencies, mpl::second<mpl::_1> > |
| >::type |
| feature_vector_with_dependencies; |
| |
| // sort the features according to which is derived from which |
| typedef |
| typename mpl::sort< |
| feature_vector_with_dependencies |
| , is_dependent_on<mpl::_2, mpl::_1> |
| >::type |
| sorted_feature_vector; |
| |
| // From the vector of features, construct a vector of accumulators |
| typedef |
| typename mpl::transform< |
| sorted_feature_vector |
| , to_accumulator<mpl::_1, Sample, Weight> |
| >::type |
| type; |
| }; |
| |
| } // namespace detail |
| |
| }} // namespace boost::accumulators |
| |
| #endif |