/////////////////////////////////////////////////////////////////////////////// // 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 #include #include #include #include #include #include #include #include #include #include #include #include #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 { /////////////////////////////////////////////////////////////////////////// // as_feature template struct as_feature { typedef Feature type; }; /////////////////////////////////////////////////////////////////////////// // weighted_feature template struct as_weighted_feature { typedef Feature type; }; /////////////////////////////////////////////////////////////////////////// // feature_of template struct feature_of { typedef Feature type; }; namespace detail { /////////////////////////////////////////////////////////////////////////// // feature_tag template struct feature_tag { typedef typename Accumulator::feature_tag type; }; template struct undroppable { typedef Feature type; }; template struct undroppable > { typedef Feature type; }; // For the purpose of determining whether one feature depends on another, // disregard whether the feature is droppable or not. template struct is_dependent_on : is_base_and_derived< typename feature_of::type>::type , typename undroppable::type > {}; template struct dependencies_of { typedef typename Feature::dependencies type; }; // Should use mpl::insert_range, but doesn't seem to work with mpl sets template struct set_insert_range : mpl::fold< Range , Set , mpl::insert > {}; template struct collect_abstract_features : mpl::fold< Features , mpl::set0<> , set_insert_range< mpl::insert > , collect_abstract_features > > > {}; template struct depends_on_base : mpl::inherit_linearly< typename mpl::sort< typename mpl::copy< typename collect_abstract_features::type , mpl::back_inserter > >::type , is_dependent_on >::type // Don't inherit multiply from a feature , mpl::if_< is_dependent_on , mpl::_1 , mpl::inherit > >::type { }; } /////////////////////////////////////////////////////////////////////////// /// depends_on template struct depends_on : detail::depends_on_base< typename mpl::transform< mpl::vector , as_feature >::type > { typedef mpl::false_ is_weight_accumulator; typedef typename mpl::transform< mpl::vector , as_feature >::type dependencies; }; namespace detail { template struct matches_feature { template struct apply : is_same< typename feature_of::type>::type , typename feature_of::type>::type>::type > {}; }; template struct contains_feature_of { typedef mpl::transform_view > > features_list; typedef typename feature_of::type>::type the_feature; typedef typename mpl::contains::type type; }; // This is to work around a bug in early versions of Fusion which caused // a compile error if contains_feature_of is used as a // predicate to fusion::find_if template struct contains_feature_of_ { template struct apply : contains_feature_of {}; }; template< typename First , typename Last , bool is_empty = fusion::result_of::equal_to::value > struct build_acc_list; template struct build_acc_list { typedef fusion::nil type; template static fusion::nil call(Args const &, First const&, Last const&) { return fusion::nil(); } }; template struct build_acc_list { typedef build_acc_list::type, Last> next_build_acc_list; typedef fusion::cons< typename fusion::result_of::value_of::type , typename next_build_acc_list::type> type; template 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 struct make_acc_list : build_acc_list< typename fusion::result_of::begin::type , typename fusion::result_of::end::type > {}; } template typename meta::make_acc_list::type make_acc_list(Sequence const &seq, Args const &args) { return meta::make_acc_list::call(args, fusion::begin(seq), fusion::end(seq)); } /////////////////////////////////////////////////////////////////////////// // checked_as_weighted_feature template struct checked_as_weighted_feature { typedef typename as_feature::type feature_type; typedef typename as_weighted_feature::type type; // weighted and non-weighted flavors should provide the same feature. BOOST_MPL_ASSERT(( is_same< typename feature_of::type , typename feature_of::type > )); }; /////////////////////////////////////////////////////////////////////////// // as_feature_list template struct as_feature_list : mpl::transform_view > { }; template struct as_feature_list : mpl::transform_view > { }; /////////////////////////////////////////////////////////////////////////// // accumulator_wrapper template struct accumulator_wrapper : Accumulator { typedef Feature feature_tag; accumulator_wrapper(accumulator_wrapper const &that) : Accumulator(*static_cast(&that)) { } template accumulator_wrapper(Args const &args) : Accumulator(args) { } }; /////////////////////////////////////////////////////////////////////////// // to_accumulator template struct to_accumulator { typedef accumulator_wrapper< typename mpl::apply2::type , Feature > type; }; template struct to_accumulator > { BOOST_MPL_ASSERT((is_same)); BOOST_MPL_ASSERT((is_same)); typedef accumulator_wrapper< typename mpl::apply2::type , Feature > accumulator_type; typedef typename mpl::if_< typename Feature::is_weight_accumulator , accumulator_wrapper, Feature> , accumulator_type >::type type; }; // BUGBUG work around an MPL bug wrt map insertion template struct insert_feature : mpl::eval_if< mpl::has_key::type> , mpl::identity , mpl::insert::type, Feature> > > { }; template struct insert_dependencies : mpl::fold< as_feature_list , FeatureMap , insert_dependencies< insert_feature , mpl::_2 , Weight > > { }; template struct insert_sequence : mpl::fold< // BUGBUG should use insert_range, but doesn't seem to work for maps as_feature_list , FeatureMap , insert_feature > { }; template struct make_accumulator_tuple { typedef typename mpl::fold< as_feature_list , mpl::map0<> , mpl::if_< mpl::is_sequence , insert_sequence , insert_feature > >::type feature_map; // for each element in the map, add its dependencies also typedef typename mpl::fold< feature_map , feature_map , insert_dependencies, 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 >::type , mpl::transform_view > >::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 >::type sorted_feature_vector; // From the vector of features, construct a vector of accumulators typedef typename mpl::transform< sorted_feature_vector , to_accumulator >::type type; }; } // namespace detail }} // namespace boost::accumulators #endif