1 ///////////////////////////////////////////////////////////////////////////////
4 // Copyright 2005 Eric Niebler. Distributed under the Boost
5 // Software License, Version 1.0. (See accompanying file
6 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 #ifndef BOOST_ACCUMULATORS_FRAMEWORK_DEPENDS_ON_HPP_EAN_28_10_2005
9 #define BOOST_ACCUMULATORS_FRAMEWORK_DEPENDS_ON_HPP_EAN_28_10_2005
11 #include <boost/version.hpp>
12 #include <boost/mpl/end.hpp>
13 #include <boost/mpl/map.hpp>
14 #include <boost/mpl/set.hpp>
15 #include <boost/mpl/copy.hpp>
16 #include <boost/mpl/fold.hpp>
17 #include <boost/mpl/size.hpp>
18 #include <boost/mpl/sort.hpp>
19 #include <boost/mpl/insert.hpp>
20 #include <boost/mpl/assert.hpp>
21 #include <boost/mpl/remove.hpp>
22 #include <boost/mpl/vector.hpp>
23 #include <boost/mpl/inherit.hpp>
24 #include <boost/mpl/identity.hpp>
25 #include <boost/mpl/equal_to.hpp>
26 #include <boost/mpl/contains.hpp>
27 #include <boost/mpl/transform.hpp>
28 #include <boost/mpl/is_sequence.hpp>
29 #include <boost/mpl/placeholders.hpp>
30 #include <boost/mpl/insert_range.hpp>
31 #include <boost/mpl/back_inserter.hpp>
32 #include <boost/mpl/transform_view.hpp>
33 #include <boost/mpl/inherit_linearly.hpp>
34 #include <boost/type_traits/is_base_and_derived.hpp>
35 #include <boost/preprocessor/repetition/repeat.hpp>
36 #include <boost/preprocessor/repetition/enum_params.hpp>
37 #include <boost/preprocessor/facilities/intercept.hpp>
38 #include <boost/accumulators/accumulators_fwd.hpp>
39 #include <boost/fusion/include/next.hpp>
40 #include <boost/fusion/include/equal_to.hpp>
41 #include <boost/fusion/include/value_of.hpp>
42 #include <boost/fusion/include/mpl.hpp>
43 #include <boost/fusion/include/end.hpp>
44 #include <boost/fusion/include/begin.hpp>
45 #include <boost/fusion/include/cons.hpp>
47 namespace boost { namespace accumulators
49 ///////////////////////////////////////////////////////////////////////////
51 template<typename Feature>
57 ///////////////////////////////////////////////////////////////////////////
59 template<typename Feature>
60 struct as_weighted_feature
65 ///////////////////////////////////////////////////////////////////////////
67 template<typename Feature>
75 ///////////////////////////////////////////////////////////////////////////
77 template<typename Accumulator>
80 typedef typename Accumulator::feature_tag type;
83 template<typename Feature>
89 template<typename Feature>
90 struct undroppable<tag::droppable<Feature> >
95 // For the purpose of determining whether one feature depends on another,
96 // disregard whether the feature is droppable or not.
97 template<typename A, typename B>
98 struct is_dependent_on
99 : is_base_and_derived<
100 typename feature_of<typename undroppable<B>::type>::type
101 , typename undroppable<A>::type
105 template<typename Feature>
106 struct dependencies_of
108 typedef typename Feature::dependencies type;
111 // Should use mpl::insert_range, but doesn't seem to work with mpl sets
112 template<typename Set, typename Range>
113 struct set_insert_range
117 , mpl::insert<mpl::_1, mpl::_2>
121 template<typename Features>
122 struct collect_abstract_features
127 mpl::insert<mpl::_1, feature_of<mpl::_2> >
128 , collect_abstract_features<dependencies_of<mpl::_2> >
133 template<typename Features>
134 struct depends_on_base
135 : mpl::inherit_linearly<
138 typename collect_abstract_features<Features>::type
139 , mpl::back_inserter<mpl::vector0<> >
141 , is_dependent_on<mpl::_1, mpl::_2>
143 // Don't inherit multiply from a feature
145 is_dependent_on<mpl::_1, mpl::_2>
147 , mpl::inherit<mpl::_1, mpl::_2>
154 ///////////////////////////////////////////////////////////////////////////
156 template<BOOST_PP_ENUM_PARAMS(BOOST_ACCUMULATORS_MAX_FEATURES, typename Feature)>
158 : detail::depends_on_base<
159 typename mpl::transform<
160 mpl::vector<BOOST_PP_ENUM_PARAMS(BOOST_ACCUMULATORS_MAX_FEATURES, Feature)>
161 , as_feature<mpl::_1>
165 typedef mpl::false_ is_weight_accumulator;
167 typename mpl::transform<
168 mpl::vector<BOOST_PP_ENUM_PARAMS(BOOST_ACCUMULATORS_MAX_FEATURES, Feature)>
169 , as_feature<mpl::_1>
176 template<typename Feature>
177 struct matches_feature
179 template<typename Accumulator>
182 typename feature_of<typename as_feature<Feature>::type>::type
183 , typename feature_of<typename as_feature<typename feature_tag<Accumulator>::type>::type>::type
188 template<typename Features, typename Accumulator>
189 struct contains_feature_of
192 mpl::transform_view<Features, feature_of<as_feature<mpl::_> > >
196 typename feature_of<typename feature_tag<Accumulator>::type>::type
200 typename mpl::contains<features_list, the_feature>::type
204 // This is to work around a bug in early versions of Fusion which caused
205 // a compile error if contains_feature_of<List, mpl::_> is used as a
206 // predicate to fusion::find_if
207 template<typename Features>
208 struct contains_feature_of_
210 template<typename Accumulator>
212 : contains_feature_of<Features, Accumulator>
219 , bool is_empty = fusion::result_of::equal_to<First, Last>::value
221 struct build_acc_list;
223 template<typename First, typename Last>
224 struct build_acc_list<First, Last, true>
226 typedef fusion::nil_ type;
228 template<typename Args>
230 call(Args const &, First const&, Last const&)
232 return fusion::nil_();
236 template<typename First, typename Last>
237 struct build_acc_list<First, Last, false>
240 build_acc_list<typename fusion::result_of::next<First>::type, Last>
243 typedef fusion::cons<
244 typename fusion::result_of::value_of<First>::type
245 , typename next_build_acc_list::type>
248 template<typename Args>
250 call(Args const &args, First const& f, Last const& l)
252 return type(args, next_build_acc_list::call(args, fusion::next(f), l));
258 template<typename Sequence>
261 typename fusion::result_of::begin<Sequence>::type
262 , typename fusion::result_of::end<Sequence>::type
267 template<typename Sequence, typename Args>
268 typename meta::make_acc_list<Sequence>::type
269 make_acc_list(Sequence const &seq, Args const &args)
271 return meta::make_acc_list<Sequence>::call(args, fusion::begin(seq), fusion::end(seq));
274 ///////////////////////////////////////////////////////////////////////////
275 // checked_as_weighted_feature
276 template<typename Feature>
277 struct checked_as_weighted_feature
279 typedef typename as_feature<Feature>::type feature_type;
280 typedef typename as_weighted_feature<feature_type>::type type;
281 // weighted and non-weighted flavors should provide the same feature.
284 typename feature_of<feature_type>::type
285 , typename feature_of<type>::type
290 ///////////////////////////////////////////////////////////////////////////
292 template<typename Features, typename Weight>
293 struct as_feature_list
294 : mpl::transform_view<Features, checked_as_weighted_feature<mpl::_1> >
298 template<typename Features>
299 struct as_feature_list<Features, void>
300 : mpl::transform_view<Features, as_feature<mpl::_1> >
304 ///////////////////////////////////////////////////////////////////////////
305 // accumulator_wrapper
306 template<typename Accumulator, typename Feature>
307 struct accumulator_wrapper
310 typedef Feature feature_tag;
312 accumulator_wrapper(accumulator_wrapper const &that)
313 : Accumulator(*static_cast<Accumulator const *>(&that))
317 template<typename Args>
318 accumulator_wrapper(Args const &args)
324 ///////////////////////////////////////////////////////////////////////////
326 template<typename Feature, typename Sample, typename Weight>
327 struct to_accumulator
331 typename mpl::apply2<typename Feature::impl, Sample, Weight>::type
337 template<typename Feature, typename Sample, typename Weight, typename Tag, typename AccumulatorSet>
338 struct to_accumulator<Feature, Sample, tag::external<Weight, Tag, AccumulatorSet> >
340 BOOST_MPL_ASSERT((is_same<Tag, void>));
341 BOOST_MPL_ASSERT((is_same<AccumulatorSet, void>));
345 typename mpl::apply2<typename Feature::impl, Sample, Weight>::type
352 typename Feature::is_weight_accumulator
353 , accumulator_wrapper<impl::external_impl<accumulator_type, tag::weights>, Feature>
359 // BUGBUG work around an MPL bug wrt map insertion
360 template<typename FeatureMap, typename Feature>
361 struct insert_feature
363 mpl::has_key<FeatureMap, typename feature_of<Feature>::type>
364 , mpl::identity<FeatureMap>
365 , mpl::insert<FeatureMap, mpl::pair<typename feature_of<Feature>::type, Feature> >
370 template<typename FeatureMap, typename Feature, typename Weight>
371 struct insert_dependencies
373 as_feature_list<typename Feature::dependencies, Weight>
375 , insert_dependencies<
376 insert_feature<mpl::_1, mpl::_2>
384 template<typename FeatureMap, typename Features, typename Weight>
385 struct insert_sequence
386 : mpl::fold< // BUGBUG should use insert_range, but doesn't seem to work for maps
387 as_feature_list<Features, Weight>
389 , insert_feature<mpl::_1, mpl::_2>
394 template<typename Features, typename Sample, typename Weight>
395 struct make_accumulator_tuple
399 as_feature_list<Features, Weight>
402 mpl::is_sequence<mpl::_2>
403 , insert_sequence<mpl::_1, mpl::_2, Weight>
404 , insert_feature<mpl::_1, mpl::_2>
409 // for each element in the map, add its dependencies also
414 , insert_dependencies<mpl::_1, mpl::second<mpl::_2>, Weight>
416 feature_map_with_dependencies;
418 // turn the map into a vector so we can sort it
420 typename mpl::insert_range<
422 , mpl::end<mpl::vector<> >::type
423 , mpl::transform_view<feature_map_with_dependencies, mpl::second<mpl::_1> >
425 feature_vector_with_dependencies;
427 // sort the features according to which is derived from which
430 feature_vector_with_dependencies
431 , is_dependent_on<mpl::_2, mpl::_1>
433 sorted_feature_vector;
435 // From the vector of features, construct a vector of accumulators
437 typename mpl::transform<
438 sorted_feature_vector
439 , to_accumulator<mpl::_1, Sample, Weight>
444 } // namespace detail
446 }} // namespace boost::accumulators