1///////////////////////////////////////////////////////////////////////////////
2// accumulator_set.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_ACCUMULATOR_SET_HPP_EAN_28_10_2005
9#define BOOST_ACCUMULATORS_FRAMEWORK_ACCUMULATOR_SET_HPP_EAN_28_10_2005
10
11#include <boost/version.hpp>
12#include <boost/mpl/bool.hpp>
13#include <boost/mpl/if.hpp>
14#include <boost/mpl/apply.hpp>
15#include <boost/mpl/assert.hpp>
16#include <boost/mpl/protect.hpp>
17#include <boost/mpl/identity.hpp>
18#include <boost/mpl/is_sequence.hpp>
19#include <boost/type_traits/is_same.hpp>
20#include <boost/type_traits/is_base_of.hpp>
21#include <boost/type_traits/remove_const.hpp>
22#include <boost/type_traits/remove_reference.hpp>
23#include <boost/core/enable_if.hpp>
24#include <boost/parameter/is_argument_pack.hpp>
25#include <boost/preprocessor/repetition/repeat_from_to.hpp>
26#include <boost/preprocessor/repetition/enum_params.hpp>
27#include <boost/preprocessor/repetition/enum_binary_params.hpp>
28#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
29#include <boost/accumulators/accumulators_fwd.hpp>
30#include <boost/accumulators/framework/depends_on.hpp>
31#include <boost/accumulators/framework/accumulator_concept.hpp>
32#include <boost/accumulators/framework/parameters/accumulator.hpp>
33#include <boost/accumulators/framework/parameters/sample.hpp>
34#include <boost/accumulators/framework/accumulators/external_accumulator.hpp>
35#include <boost/accumulators/framework/accumulators/droppable_accumulator.hpp>
36#include <boost/fusion/include/any.hpp>
37#include <boost/fusion/include/find_if.hpp>
38#include <boost/fusion/include/for_each.hpp>
39#include <boost/fusion/include/filter_view.hpp>
40
41namespace boost { namespace accumulators
42{
43
44namespace detail
45{
46 ///////////////////////////////////////////////////////////////////////////////
47 // accumulator_visitor
48 // wrap a boost::parameter argument pack in a Fusion extractor object
49 template<typename Args>
50 struct accumulator_visitor
51 {
52 explicit accumulator_visitor(Args const &a)
53 : args(a)
54 {
55 }
56
57 template<typename Accumulator>
58 void operator ()(Accumulator &accumulator) const
59 {
60 accumulator(this->args);
61 }
62
63 private:
64 accumulator_visitor &operator =(accumulator_visitor const &);
65 Args const &args;
66 };
67
68 template<typename Args>
69 inline accumulator_visitor<Args> const make_accumulator_visitor(Args const &args)
70 {
71 return accumulator_visitor<Args>(args);
72 }
73
74 ///////////////////////////////////////////////////////////////////////////////
75 // accumulator_set_base
76 struct accumulator_set_base
77 {
78 };
79
80 ///////////////////////////////////////////////////////////////////////////////
81 // is_accumulator_set
82 template<typename T>
83 struct is_accumulator_set
84 : mpl::if_<
85 boost::is_base_of<
86 accumulator_set_base
87 , typename boost::remove_const<
88 typename boost::remove_reference<T>::type
89 >::type
90 >
91 , mpl::true_
92 , mpl::false_
93 >::type
94 {
95 };
96
97 // function object that serialize an accumulator
98 template<typename Archive>
99 struct serialize_accumulator
100 {
101 serialize_accumulator(Archive & _ar, const unsigned int _file_version) :
102 ar(_ar), file_version(_file_version)
103 {}
104
105 template<typename Accumulator>
106 void operator ()(Accumulator &accumulator)
107 {
108 accumulator.serialize(ar, file_version);
109 }
110
111 private:
112 Archive& ar;
113 const unsigned int file_version;
114 };
115
116} // namespace detail
117
118#ifdef _MSC_VER
119#pragma warning(push)
120#pragma warning(disable: 4355) // warning C4355: 'this' : used in base member initializer list
121#endif
122
123///////////////////////////////////////////////////////////////////////////////
124/// \brief A set of accumulators.
125///
126/// accumulator_set resolves the dependencies between features and ensures that
127/// the accumulators in the set are updated in the proper order.
128///
129/// acccumulator_set provides a general mechanism to visit the accumulators
130/// in the set in order, with or without a filter. You can also fetch a reference
131/// to an accumulator that corresponds to a feature.
132///
133template<typename Sample, typename Features, typename Weight>
134struct accumulator_set
135 : detail::accumulator_set_base
136{
137 typedef Sample sample_type; ///< The type of the samples that will be accumulated
138 typedef Features features_type; ///< An MPL sequence of the features that should be accumulated.
139 typedef Weight weight_type; ///< The type of the weight parameter. Must be a scalar. Defaults to void.
140
141 /// INTERNAL ONLY
142 ///
143 typedef
144 typename detail::make_accumulator_tuple<
145 Features
146 , Sample
147 , Weight
148 >::type
149 accumulators_mpl_vector;
150
151 // generate a fusion::list of accumulators
152 /// INTERNAL ONLY
153 ///
154 typedef
155 typename detail::meta::make_acc_list<
156 accumulators_mpl_vector
157 >::type
158 accumulators_type;
159
160 /// INTERNAL ONLY
161 ///
162 //BOOST_MPL_ASSERT((mpl::is_sequence<accumulators_type>));
163
164 ///////////////////////////////////////////////////////////////////////////////
165 /// default-construct all contained accumulators
166 accumulator_set()
167 : accumulators(
168 detail::make_acc_list(
169 accumulators_mpl_vector()
170 , (boost::accumulators::accumulator = *this)
171 )
172 )
173 {
174 // Add-ref the Features that the user has specified
175 this->template visit_if<detail::contains_feature_of_<Features> >(
176 detail::make_add_ref_visitor(boost::accumulators::accumulator = *this)
177 );
178 }
179
180 /// \overload
181 ///
182 /// \param a1 Optional named parameter to be passed to all the accumulators
183 template<typename A1>
184 explicit accumulator_set(
185 A1 const &a1
186 , typename boost::enable_if<
187 parameter::is_argument_pack<A1>
188 , detail::_enabler
189 >::type = detail::_enabler()
190 ) : accumulators(
191 detail::make_acc_list(
192 accumulators_mpl_vector()
193 , (boost::accumulators::accumulator = *this, a1)
194 )
195 )
196 {
197 // Add-ref the Features that the user has specified
198 this->template visit_if<detail::contains_feature_of_<Features> >(
199 detail::make_add_ref_visitor(boost::accumulators::accumulator = *this)
200 );
201 }
202
203 /// \overload
204 ///
205 /// \param a1 Optional sample parameter to be passed to all the accumulators
206 template<typename A1>
207 explicit accumulator_set(
208 A1 const &a1
209 , typename boost::disable_if<
210 parameter::is_argument_pack<A1>
211 , detail::_enabler
212 >::type = detail::_enabler()
213 ) : accumulators(
214 detail::make_acc_list(
215 accumulators_mpl_vector()
216 , (
217 boost::accumulators::accumulator = *this
218 , boost::accumulators::sample = a1
219 )
220 )
221 )
222 {
223 // Add-ref the Features that the user has specified
224 this->template visit_if<detail::contains_feature_of_<Features> >(
225 detail::make_add_ref_visitor(boost::accumulators::accumulator = *this)
226 );
227 }
228
229 // ... other overloads generated by Boost.Preprocessor:
230
231 /// INTERNAL ONLY
232 ///
233#define BOOST_ACCUMULATORS_ACCUMULATOR_SET_CTOR(z, n, _) \
234 template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
235 accumulator_set( \
236 BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a) \
237 , typename boost::enable_if< \
238 parameter::is_argument_pack<A0> \
239 , detail::_enabler \
240 >::type = detail::_enabler() \
241 ) : accumulators( \
242 detail::make_acc_list( \
243 accumulators_mpl_vector() \
244 , ( \
245 boost::accumulators::accumulator = *this \
246 BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \
247 ) \
248 ) \
249 ) \
250 { \
251 /* Add-ref the Features that the user has specified */ \
252 this->template visit_if<detail::contains_feature_of_<Features> >( \
253 detail::make_add_ref_visitor(boost::accumulators::accumulator = *this) \
254 ); \
255 } \
256 template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
257 accumulator_set( \
258 BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a) \
259 , typename boost::disable_if< \
260 parameter::is_argument_pack<A0> \
261 , detail::_enabler \
262 >::type = detail::_enabler() \
263 ) : accumulators( \
264 detail::make_acc_list( \
265 accumulators_mpl_vector() \
266 , ( \
267 boost::accumulators::accumulator = *this \
268 , boost::accumulators::sample = BOOST_PP_ENUM_PARAMS_Z(z, n, a) \
269 ) \
270 ) \
271 ) \
272 { \
273 /* Add-ref the Features that the user has specified */ \
274 this->template visit_if<detail::contains_feature_of_<Features> >( \
275 detail::make_add_ref_visitor(boost::accumulators::accumulator = *this) \
276 ); \
277 }
278
279 /// INTERNAL ONLY
280 ///
281 BOOST_PP_REPEAT_FROM_TO(
282 2
283 , BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
284 , BOOST_ACCUMULATORS_ACCUMULATOR_SET_CTOR
285 , _
286 )
287
288 #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
289 /// \overload
290 ///
291 template<typename A1, typename A2, ...>
292 accumulator_set(A1 const &a1, A2 const &a2, ...);
293 #endif
294
295 // ... other overloads generated by Boost.Preprocessor below ...
296
297 ///////////////////////////////////////////////////////////////////////////////
298 /// Visitation
299 /// \param func UnaryFunction which is invoked with each accumulator in turn.
300 template<typename UnaryFunction>
301 void visit(UnaryFunction const &func)
302 {
303 fusion::for_each(this->accumulators, func);
304 }
305
306 ///////////////////////////////////////////////////////////////////////////////
307 /// Conditional visitation
308 /// \param func UnaryFunction which is invoked with each accumulator in turn,
309 /// provided the accumulator satisfies the MPL predicate FilterPred.
310 template<typename FilterPred, typename UnaryFunction>
311 void visit_if(UnaryFunction const &func)
312 {
313 fusion::filter_view<accumulators_type, FilterPred> filtered_accs(this->accumulators);
314 fusion::for_each(filtered_accs, func);
315 }
316
317 ///////////////////////////////////////////////////////////////////////////////
318 /// The return type of the operator() overloads is void.
319 typedef void result_type;
320
321 ///////////////////////////////////////////////////////////////////////////////
322 /// Accumulation
323 /// \param a1 Optional named parameter to be passed to all the accumulators
324 void operator ()()
325 {
326 this->visit(
327 detail::make_accumulator_visitor(
328 boost::accumulators::accumulator = *this
329 )
330 );
331 }
332
333 // ... other overloads generated by Boost.Preprocessor:
334
335 /// INTERNAL ONLY
336 ///
337#define BOOST_ACCUMULATORS_ACCUMULATOR_SET_FUN_OP(z, n, _) \
338 template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
339 void operator ()( \
340 BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a) \
341 , typename boost::enable_if< \
342 parameter::is_argument_pack<A0> \
343 , detail::_enabler \
344 >::type = detail::_enabler() \
345 ) \
346 { \
347 this->visit( \
348 detail::make_accumulator_visitor( \
349 ( \
350 boost::accumulators::accumulator = *this \
351 BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \
352 ) \
353 ) \
354 ); \
355 } \
356 template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
357 void operator ()( \
358 BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a) \
359 , typename boost::disable_if< \
360 parameter::is_argument_pack<A0> \
361 , detail::_enabler \
362 >::type = detail::_enabler() \
363 ) \
364 { \
365 this->visit( \
366 detail::make_accumulator_visitor( \
367 ( \
368 boost::accumulators::accumulator = *this \
369 , boost::accumulators::sample = BOOST_PP_ENUM_PARAMS_Z(z, n, a) \
370 ) \
371 ) \
372 ); \
373 }
374
375 /// INTERNAL ONLY
376 ///
377 BOOST_PP_REPEAT_FROM_TO(
378 1
379 , BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
380 , BOOST_ACCUMULATORS_ACCUMULATOR_SET_FUN_OP
381 , _
382 )
383
384 #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
385 /// \overload
386 ///
387 template<typename A1, typename A2, ...>
388 void operator ()(A1 const &a1, A2 const &a2, ...);
389 #endif
390
391 ///////////////////////////////////////////////////////////////////////////////
392 /// Extraction
393 template<typename Feature>
394 struct apply
395 : fusion::result_of::value_of<
396 typename fusion::result_of::find_if<
397 accumulators_type
398 , detail::matches_feature<Feature>
399 >::type
400 >
401 {
402 };
403
404 ///////////////////////////////////////////////////////////////////////////////
405 /// Extraction
406 template<typename Feature>
407 typename apply<Feature>::type &extract()
408 {
409 return *fusion::find_if<detail::matches_feature<Feature> >(this->accumulators);
410 }
411
412 /// \overload
413 template<typename Feature>
414 typename apply<Feature>::type const &extract() const
415 {
416 return *fusion::find_if<detail::matches_feature<Feature> >(this->accumulators);
417 }
418
419 ///////////////////////////////////////////////////////////////////////////////
420 /// Drop
421 template<typename Feature>
422 void drop()
423 {
424 // You can only drop the features that you have specified explicitly
425 typedef typename apply<Feature>::type the_accumulator;
426 BOOST_MPL_ASSERT((detail::contains_feature_of<Features, the_accumulator>));
427
428 typedef
429 typename feature_of<typename as_feature<Feature>::type>::type
430 the_feature;
431
432 (*fusion::find_if<detail::matches_feature<Feature> >(this->accumulators))
433 .drop(boost::accumulators::accumulator = *this);
434
435 // Also drop accumulators that this feature depends on
436 typedef typename the_feature::dependencies dependencies;
437 this->template visit_if<detail::contains_feature_of_<dependencies> >(
438 detail::make_drop_visitor(boost::accumulators::accumulator = *this)
439 );
440 }
441
442 // make the accumulator set serializeable
443 template<class Archive>
444 void serialize(Archive & ar, const unsigned int file_version)
445 {
446 detail::serialize_accumulator<Archive> serializer(ar, file_version);
447 fusion::for_each(this->accumulators, serializer);
448 }
449
450private:
451
452 accumulators_type accumulators;
453};
454
455#ifdef _MSC_VER
456#pragma warning(pop)
457#endif
458
459///////////////////////////////////////////////////////////////////////////////
460// find_accumulator
461// find an accumulator in an accumulator_set corresponding to a feature
462template<typename Feature, typename AccumulatorSet>
463typename mpl::apply<AccumulatorSet, Feature>::type &
464find_accumulator(AccumulatorSet &acc BOOST_ACCUMULATORS_PROTO_DISABLE_IF_IS_CONST(AccumulatorSet))
465{
466 return acc.template extract<Feature>();
467}
468
469/// \overload
470template<typename Feature, typename AccumulatorSet>
471typename mpl::apply<AccumulatorSet, Feature>::type const &
472find_accumulator(AccumulatorSet const &acc)
473{
474 return acc.template extract<Feature>();
475}
476
477template<typename Feature, typename AccumulatorSet>
478typename mpl::apply<AccumulatorSet, Feature>::type::result_type
479extract_result(AccumulatorSet const &acc)
480{
481 return find_accumulator<Feature>(acc).result(
482 boost::accumulators::accumulator = acc
483 );
484}
485
486///////////////////////////////////////////////////////////////////////////////
487// extract_result
488// extract a result from an accumulator set
489/// INTERNAL ONLY
490///
491#define BOOST_ACCUMULATORS_EXTRACT_RESULT_FUN(z, n, _) \
492 template< \
493 typename Feature \
494 , typename AccumulatorSet \
495 BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, typename A) \
496 > \
497 typename mpl::apply<AccumulatorSet, Feature>::type::result_type \
498 extract_result( \
499 AccumulatorSet const &acc \
500 BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(z, n, A, const &a) \
501 , typename boost::enable_if< \
502 parameter::is_argument_pack<A0> \
503 , detail::_enabler \
504 >::type \
505 ) \
506 { \
507 return find_accumulator<Feature>(acc).result( \
508 ( \
509 boost::accumulators::accumulator = acc \
510 BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \
511 ) \
512 ); \
513 } \
514 template< \
515 typename Feature \
516 , typename AccumulatorSet \
517 BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, typename A) \
518 > \
519 typename mpl::apply<AccumulatorSet, Feature>::type::result_type \
520 extract_result( \
521 AccumulatorSet const &acc \
522 BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(z, n, A, const &a) \
523 , typename boost::disable_if< \
524 parameter::is_argument_pack<A0> \
525 , detail::_enabler \
526 >::type \
527 ) \
528 { \
529 return find_accumulator<Feature>(acc).result(( \
530 boost::accumulators::accumulator = acc \
531 , boost::accumulators::sample = BOOST_PP_ENUM_PARAMS_Z(z, n, a) \
532 )); \
533 }
534
535BOOST_PP_REPEAT_FROM_TO(
536 1
537 , BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
538 , BOOST_ACCUMULATORS_EXTRACT_RESULT_FUN
539 , _
540)
541
542}} // namespace boost::accumulators
543
544#endif
545

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