You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
411 lines
13 KiB
411 lines
13 KiB
/////////////////////////////////////////////////////////////////////////////// |
|
// 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
|
|
|