1///////////////////////////////////////////////////////////////////////////////
2// depends_on.hpp
3//
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)
7
8#ifndef BOOST_ACCUMULATORS_FRAMEWORK_DEPENDS_ON_HPP_EAN_28_10_2005
9#define BOOST_ACCUMULATORS_FRAMEWORK_DEPENDS_ON_HPP_EAN_28_10_2005
10
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>
46
47namespace boost { namespace accumulators
48{
49 ///////////////////////////////////////////////////////////////////////////
50 // as_feature
51 template<typename Feature>
52 struct as_feature
53 {
54 typedef Feature type;
55 };
56
57 ///////////////////////////////////////////////////////////////////////////
58 // weighted_feature
59 template<typename Feature>
60 struct as_weighted_feature
61 {
62 typedef Feature type;
63 };
64
65 ///////////////////////////////////////////////////////////////////////////
66 // feature_of
67 template<typename Feature>
68 struct feature_of
69 {
70 typedef Feature type;
71 };
72
73 namespace detail
74 {
75 ///////////////////////////////////////////////////////////////////////////
76 // feature_tag
77 template<typename Accumulator>
78 struct feature_tag
79 {
80 typedef typename Accumulator::feature_tag type;
81 };
82
83 template<typename Feature>
84 struct undroppable
85 {
86 typedef Feature type;
87 };
88
89 template<typename Feature>
90 struct undroppable<tag::droppable<Feature> >
91 {
92 typedef Feature type;
93 };
94
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
102 >
103 {};
104
105 template<typename Feature>
106 struct dependencies_of
107 {
108 typedef typename Feature::dependencies type;
109 };
110
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
114 : mpl::fold<
115 Range
116 , Set
117 , mpl::insert<mpl::_1, mpl::_2>
118 >
119 {};
120
121 template<typename Features>
122 struct collect_abstract_features
123 : mpl::fold<
124 Features
125 , mpl::set0<>
126 , set_insert_range<
127 mpl::insert<mpl::_1, feature_of<mpl::_2> >
128 , collect_abstract_features<dependencies_of<mpl::_2> >
129 >
130 >
131 {};
132
133 template<typename Features>
134 struct depends_on_base
135 : mpl::inherit_linearly<
136 typename mpl::sort<
137 typename mpl::copy<
138 typename collect_abstract_features<Features>::type
139 , mpl::back_inserter<mpl::vector0<> >
140 >::type
141 , is_dependent_on<mpl::_1, mpl::_2>
142 >::type
143 // Don't inherit multiply from a feature
144 , mpl::if_<
145 is_dependent_on<mpl::_1, mpl::_2>
146 , mpl::_1
147 , mpl::inherit<mpl::_1, mpl::_2>
148 >
149 >::type
150 {
151 };
152 }
153
154 ///////////////////////////////////////////////////////////////////////////
155 /// depends_on
156 template<BOOST_PP_ENUM_PARAMS(BOOST_ACCUMULATORS_MAX_FEATURES, typename Feature)>
157 struct depends_on
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>
162 >::type
163 >
164 {
165 typedef mpl::false_ is_weight_accumulator;
166 typedef
167 typename mpl::transform<
168 mpl::vector<BOOST_PP_ENUM_PARAMS(BOOST_ACCUMULATORS_MAX_FEATURES, Feature)>
169 , as_feature<mpl::_1>
170 >::type
171 dependencies;
172 };
173
174 namespace detail
175 {
176 template<typename Feature>
177 struct matches_feature
178 {
179 template<typename Accumulator>
180 struct apply
181 : is_same<
182 typename feature_of<typename as_feature<Feature>::type>::type
183 , typename feature_of<typename as_feature<typename feature_tag<Accumulator>::type>::type>::type
184 >
185 {};
186 };
187
188 template<typename Features, typename Accumulator>
189 struct contains_feature_of
190 {
191 typedef
192 mpl::transform_view<Features, feature_of<as_feature<mpl::_> > >
193 features_list;
194
195 typedef
196 typename feature_of<typename feature_tag<Accumulator>::type>::type
197 the_feature;
198
199 typedef
200 typename mpl::contains<features_list, the_feature>::type
201 type;
202 };
203
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_
209 {
210 template<typename Accumulator>
211 struct apply
212 : contains_feature_of<Features, Accumulator>
213 {};
214 };
215
216 template<
217 typename First
218 , typename Last
219 , bool is_empty = fusion::result_of::equal_to<First, Last>::value
220 >
221 struct build_acc_list;
222
223 template<typename First, typename Last>
224 struct build_acc_list<First, Last, true>
225 {
226 typedef fusion::nil_ type;
227
228 template<typename Args>
229 static fusion::nil_
230 call(Args const &, First const&, Last const&)
231 {
232 return fusion::nil_();
233 }
234 };
235
236 template<typename First, typename Last>
237 struct build_acc_list<First, Last, false>
238 {
239 typedef
240 build_acc_list<typename fusion::result_of::next<First>::type, Last>
241 next_build_acc_list;
242
243 typedef fusion::cons<
244 typename fusion::result_of::value_of<First>::type
245 , typename next_build_acc_list::type>
246 type;
247
248 template<typename Args>
249 static type
250 call(Args const &args, First const& f, Last const& l)
251 {
252 return type(args, next_build_acc_list::call(args, fusion::next(f), l));
253 }
254 };
255
256 namespace meta
257 {
258 template<typename Sequence>
259 struct make_acc_list
260 : build_acc_list<
261 typename fusion::result_of::begin<Sequence>::type
262 , typename fusion::result_of::end<Sequence>::type
263 >
264 {};
265 }
266
267 template<typename Sequence, typename Args>
268 typename meta::make_acc_list<Sequence>::type
269 make_acc_list(Sequence &seq, Args const &args)
270 {
271 return meta::make_acc_list<Sequence>::call(args, fusion::begin(seq), fusion::end(seq));
272 }
273
274 template<typename Sequence, typename Args>
275 typename meta::make_acc_list<Sequence>::type
276 make_acc_list(Sequence const &seq, Args const &args)
277 {
278 return meta::make_acc_list<Sequence const>::call(args, fusion::begin(seq), fusion::end(seq));
279 }
280
281 ///////////////////////////////////////////////////////////////////////////
282 // checked_as_weighted_feature
283 template<typename Feature>
284 struct checked_as_weighted_feature
285 {
286 typedef typename as_feature<Feature>::type feature_type;
287 typedef typename as_weighted_feature<feature_type>::type type;
288 // weighted and non-weighted flavors should provide the same feature.
289 BOOST_MPL_ASSERT((
290 is_same<
291 typename feature_of<feature_type>::type
292 , typename feature_of<type>::type
293 >
294 ));
295 };
296
297 ///////////////////////////////////////////////////////////////////////////
298 // as_feature_list
299 template<typename Features, typename Weight>
300 struct as_feature_list
301 : mpl::transform_view<Features, checked_as_weighted_feature<mpl::_1> >
302 {
303 };
304
305 template<typename Features>
306 struct as_feature_list<Features, void>
307 : mpl::transform_view<Features, as_feature<mpl::_1> >
308 {
309 };
310
311 ///////////////////////////////////////////////////////////////////////////
312 // accumulator_wrapper
313 template<typename Accumulator, typename Feature>
314 struct accumulator_wrapper
315 : Accumulator
316 {
317 typedef Feature feature_tag;
318
319 accumulator_wrapper(accumulator_wrapper const &that)
320 : Accumulator(*static_cast<Accumulator const *>(&that))
321 {
322 }
323
324 template<typename Args>
325 accumulator_wrapper(Args const &args)
326 : Accumulator(args)
327 {
328 }
329 };
330
331 ///////////////////////////////////////////////////////////////////////////
332 // to_accumulator
333 template<typename Feature, typename Sample, typename Weight>
334 struct to_accumulator
335 {
336 typedef
337 accumulator_wrapper<
338 typename mpl::apply2<typename Feature::impl, Sample, Weight>::type
339 , Feature
340 >
341 type;
342 };
343
344 template<typename Feature, typename Sample, typename Weight, typename Tag, typename AccumulatorSet>
345 struct to_accumulator<Feature, Sample, tag::external<Weight, Tag, AccumulatorSet> >
346 {
347 BOOST_MPL_ASSERT((is_same<Tag, void>));
348 BOOST_MPL_ASSERT((is_same<AccumulatorSet, void>));
349
350 typedef
351 accumulator_wrapper<
352 typename mpl::apply2<typename Feature::impl, Sample, Weight>::type
353 , Feature
354 >
355 accumulator_type;
356
357 typedef
358 typename mpl::if_<
359 typename Feature::is_weight_accumulator
360 , accumulator_wrapper<impl::external_impl<accumulator_type, tag::weights>, Feature>
361 , accumulator_type
362 >::type
363 type;
364 };
365
366 // BUGBUG work around an MPL bug wrt map insertion
367 template<typename FeatureMap, typename Feature>
368 struct insert_feature
369 : mpl::eval_if<
370 mpl::has_key<FeatureMap, typename feature_of<Feature>::type>
371 , mpl::identity<FeatureMap>
372 , mpl::insert<FeatureMap, mpl::pair<typename feature_of<Feature>::type, Feature> >
373 >
374 {
375 };
376
377 template<typename FeatureMap, typename Feature, typename Weight>
378 struct insert_dependencies
379 : mpl::fold<
380 as_feature_list<typename Feature::dependencies, Weight>
381 , FeatureMap
382 , insert_dependencies<
383 insert_feature<mpl::_1, mpl::_2>
384 , mpl::_2
385 , Weight
386 >
387 >
388 {
389 };
390
391 template<typename FeatureMap, typename Features, typename Weight>
392 struct insert_sequence
393 : mpl::fold< // BUGBUG should use insert_range, but doesn't seem to work for maps
394 as_feature_list<Features, Weight>
395 , FeatureMap
396 , insert_feature<mpl::_1, mpl::_2>
397 >
398 {
399 };
400
401 template<typename Features, typename Sample, typename Weight>
402 struct make_accumulator_tuple
403 {
404 typedef
405 typename mpl::fold<
406 as_feature_list<Features, Weight>
407 , mpl::map0<>
408 , mpl::if_<
409 mpl::is_sequence<mpl::_2>
410 , insert_sequence<mpl::_1, mpl::_2, Weight>
411 , insert_feature<mpl::_1, mpl::_2>
412 >
413 >::type
414 feature_map;
415
416 // for each element in the map, add its dependencies also
417 typedef
418 typename mpl::fold<
419 feature_map
420 , feature_map
421 , insert_dependencies<mpl::_1, mpl::second<mpl::_2>, Weight>
422 >::type
423 feature_map_with_dependencies;
424
425 // turn the map into a vector so we can sort it
426 typedef
427 typename mpl::insert_range<
428 mpl::vector<>
429 , mpl::end<mpl::vector<> >::type
430 , mpl::transform_view<feature_map_with_dependencies, mpl::second<mpl::_1> >
431 >::type
432 feature_vector_with_dependencies;
433
434 // sort the features according to which is derived from which
435 typedef
436 typename mpl::sort<
437 feature_vector_with_dependencies
438 , is_dependent_on<mpl::_2, mpl::_1>
439 >::type
440 sorted_feature_vector;
441
442 // From the vector of features, construct a vector of accumulators
443 typedef
444 typename mpl::transform<
445 sorted_feature_vector
446 , to_accumulator<mpl::_1, Sample, Weight>
447 >::type
448 type;
449 };
450
451 } // namespace detail
452
453}} // namespace boost::accumulators
454
455#endif
456

source code of include/boost/accumulators/framework/depends_on.hpp