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 | |
47 | namespace 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 const &seq, Args const &args) |
270 | { |
271 | return meta::make_acc_list<Sequence>::call(args, fusion::begin(seq), fusion::end(seq)); |
272 | } |
273 | |
274 | /////////////////////////////////////////////////////////////////////////// |
275 | // checked_as_weighted_feature |
276 | template<typename Feature> |
277 | struct checked_as_weighted_feature |
278 | { |
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. |
282 | BOOST_MPL_ASSERT(( |
283 | is_same< |
284 | typename feature_of<feature_type>::type |
285 | , typename feature_of<type>::type |
286 | > |
287 | )); |
288 | }; |
289 | |
290 | /////////////////////////////////////////////////////////////////////////// |
291 | // as_feature_list |
292 | template<typename Features, typename Weight> |
293 | struct as_feature_list |
294 | : mpl::transform_view<Features, checked_as_weighted_feature<mpl::_1> > |
295 | { |
296 | }; |
297 | |
298 | template<typename Features> |
299 | struct as_feature_list<Features, void> |
300 | : mpl::transform_view<Features, as_feature<mpl::_1> > |
301 | { |
302 | }; |
303 | |
304 | /////////////////////////////////////////////////////////////////////////// |
305 | // accumulator_wrapper |
306 | template<typename Accumulator, typename Feature> |
307 | struct accumulator_wrapper |
308 | : Accumulator |
309 | { |
310 | typedef Feature feature_tag; |
311 | |
312 | accumulator_wrapper(accumulator_wrapper const &that) |
313 | : Accumulator(*static_cast<Accumulator const *>(&that)) |
314 | { |
315 | } |
316 | |
317 | template<typename Args> |
318 | accumulator_wrapper(Args const &args) |
319 | : Accumulator(args) |
320 | { |
321 | } |
322 | }; |
323 | |
324 | /////////////////////////////////////////////////////////////////////////// |
325 | // to_accumulator |
326 | template<typename Feature, typename Sample, typename Weight> |
327 | struct to_accumulator |
328 | { |
329 | typedef |
330 | accumulator_wrapper< |
331 | typename mpl::apply2<typename Feature::impl, Sample, Weight>::type |
332 | , Feature |
333 | > |
334 | type; |
335 | }; |
336 | |
337 | template<typename Feature, typename Sample, typename Weight, typename Tag, typename AccumulatorSet> |
338 | struct to_accumulator<Feature, Sample, tag::external<Weight, Tag, AccumulatorSet> > |
339 | { |
340 | BOOST_MPL_ASSERT((is_same<Tag, void>)); |
341 | BOOST_MPL_ASSERT((is_same<AccumulatorSet, void>)); |
342 | |
343 | typedef |
344 | accumulator_wrapper< |
345 | typename mpl::apply2<typename Feature::impl, Sample, Weight>::type |
346 | , Feature |
347 | > |
348 | accumulator_type; |
349 | |
350 | typedef |
351 | typename mpl::if_< |
352 | typename Feature::is_weight_accumulator |
353 | , accumulator_wrapper<impl::external_impl<accumulator_type, tag::weights>, Feature> |
354 | , accumulator_type |
355 | >::type |
356 | type; |
357 | }; |
358 | |
359 | // BUGBUG work around an MPL bug wrt map insertion |
360 | template<typename FeatureMap, typename Feature> |
361 | struct insert_feature |
362 | : mpl::eval_if< |
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> > |
366 | > |
367 | { |
368 | }; |
369 | |
370 | template<typename FeatureMap, typename Feature, typename Weight> |
371 | struct insert_dependencies |
372 | : mpl::fold< |
373 | as_feature_list<typename Feature::dependencies, Weight> |
374 | , FeatureMap |
375 | , insert_dependencies< |
376 | insert_feature<mpl::_1, mpl::_2> |
377 | , mpl::_2 |
378 | , Weight |
379 | > |
380 | > |
381 | { |
382 | }; |
383 | |
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> |
388 | , FeatureMap |
389 | , insert_feature<mpl::_1, mpl::_2> |
390 | > |
391 | { |
392 | }; |
393 | |
394 | template<typename Features, typename Sample, typename Weight> |
395 | struct make_accumulator_tuple |
396 | { |
397 | typedef |
398 | typename mpl::fold< |
399 | as_feature_list<Features, Weight> |
400 | , mpl::map0<> |
401 | , mpl::if_< |
402 | mpl::is_sequence<mpl::_2> |
403 | , insert_sequence<mpl::_1, mpl::_2, Weight> |
404 | , insert_feature<mpl::_1, mpl::_2> |
405 | > |
406 | >::type |
407 | feature_map; |
408 | |
409 | // for each element in the map, add its dependencies also |
410 | typedef |
411 | typename mpl::fold< |
412 | feature_map |
413 | , feature_map |
414 | , insert_dependencies<mpl::_1, mpl::second<mpl::_2>, Weight> |
415 | >::type |
416 | feature_map_with_dependencies; |
417 | |
418 | // turn the map into a vector so we can sort it |
419 | typedef |
420 | typename mpl::insert_range< |
421 | mpl::vector<> |
422 | , mpl::end<mpl::vector<> >::type |
423 | , mpl::transform_view<feature_map_with_dependencies, mpl::second<mpl::_1> > |
424 | >::type |
425 | feature_vector_with_dependencies; |
426 | |
427 | // sort the features according to which is derived from which |
428 | typedef |
429 | typename mpl::sort< |
430 | feature_vector_with_dependencies |
431 | , is_dependent_on<mpl::_2, mpl::_1> |
432 | >::type |
433 | sorted_feature_vector; |
434 | |
435 | // From the vector of features, construct a vector of accumulators |
436 | typedef |
437 | typename mpl::transform< |
438 | sorted_feature_vector |
439 | , to_accumulator<mpl::_1, Sample, Weight> |
440 | >::type |
441 | type; |
442 | }; |
443 | |
444 | } // namespace detail |
445 | |
446 | }} // namespace boost::accumulators |
447 | |
448 | #endif |
449 | |