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/apply.hpp>
13#include <boost/mpl/assert.hpp>
14#include <boost/mpl/protect.hpp>
15#include <boost/mpl/identity.hpp>
16#include <boost/mpl/is_sequence.hpp>
17#include <boost/type_traits/is_same.hpp>
18#include <boost/type_traits/is_base_and_derived.hpp>
19#include <boost/parameter/parameters.hpp>
20#include <boost/preprocessor/repetition/repeat_from_to.hpp>
21#include <boost/preprocessor/repetition/enum_binary_params.hpp>
22#include <boost/accumulators/accumulators_fwd.hpp>
23#include <boost/accumulators/framework/depends_on.hpp>
24#include <boost/accumulators/framework/accumulator_concept.hpp>
25#include <boost/accumulators/framework/parameters/accumulator.hpp>
26#include <boost/accumulators/framework/parameters/sample.hpp>
27#include <boost/accumulators/framework/accumulators/external_accumulator.hpp>
28#include <boost/accumulators/framework/accumulators/droppable_accumulator.hpp>
29#include <boost/fusion/include/any.hpp>
30#include <boost/fusion/include/find_if.hpp>
31#include <boost/fusion/include/for_each.hpp>
32#include <boost/fusion/include/filter_view.hpp>
33
34namespace boost { namespace accumulators
35{
36
37namespace detail
38{
39 ///////////////////////////////////////////////////////////////////////////////
40 // accumulator_visitor
41 // wrap a boost::parameter argument pack in a Fusion extractor object
42 template<typename Args>
43 struct accumulator_visitor
44 {
45 explicit accumulator_visitor(Args const &a)
46 : args(a)
47 {
48 }
49
50 template<typename Accumulator>
51 void operator ()(Accumulator &accumulator) const
52 {
53 accumulator(this->args);
54 }
55
56 private:
57 accumulator_visitor &operator =(accumulator_visitor const &);
58 Args const &args;
59 };
60
61 template<typename Args>
62 inline accumulator_visitor<Args> const make_accumulator_visitor(Args const &args)
63 {
64 return accumulator_visitor<Args>(args);
65 }
66
67 typedef
68 parameter::parameters<
69 parameter::required<tag::accumulator>
70 , parameter::optional<tag::sample>
71 // ... and others which are not specified here...
72 >
73 accumulator_params;
74
75 ///////////////////////////////////////////////////////////////////////////////
76 // accumulator_set_base
77 struct accumulator_set_base
78 {
79 };
80
81 ///////////////////////////////////////////////////////////////////////////////
82 // is_accumulator_set
83 template<typename T>
84 struct is_accumulator_set
85 : is_base_and_derived<accumulator_set_base, T>
86 {
87 };
88
89} // namespace detail
90
91#ifdef _MSC_VER
92#pragma warning(push)
93#pragma warning(disable: 4355) // warning C4355: 'this' : used in base member initializer list
94#endif
95
96///////////////////////////////////////////////////////////////////////////////
97/// \brief A set of accumulators.
98///
99/// accumulator_set resolves the dependencies between features and ensures that
100/// the accumulators in the set are updated in the proper order.
101///
102/// acccumulator_set provides a general mechanism to visit the accumulators
103/// in the set in order, with or without a filter. You can also fetch a reference
104/// to an accumulator that corresponds to a feature.
105///
106template<typename Sample, typename Features, typename Weight>
107struct accumulator_set
108 : detail::accumulator_set_base
109{
110 typedef Sample sample_type; ///< The type of the samples that will be accumulated
111 typedef Features features_type; ///< An MPL sequence of the features that should be accumulated.
112 typedef Weight weight_type; ///< The type of the weight parameter. Must be a scalar. Defaults to void.
113
114 /// INTERNAL ONLY
115 ///
116 typedef
117 typename detail::make_accumulator_tuple<
118 Features
119 , Sample
120 , Weight
121 >::type
122 accumulators_mpl_vector;
123
124 // generate a fusion::list of accumulators
125 /// INTERNAL ONLY
126 ///
127 typedef
128 typename detail::meta::make_acc_list<
129 accumulators_mpl_vector
130 >::type
131 accumulators_type;
132
133 /// INTERNAL ONLY
134 ///
135 //BOOST_MPL_ASSERT((mpl::is_sequence<accumulators_type>));
136
137 ///////////////////////////////////////////////////////////////////////////////
138 /// default-construct all contained accumulators
139 accumulator_set()
140 : accumulators(
141 detail::make_acc_list(
142 accumulators_mpl_vector()
143 , detail::accumulator_params()(*this)
144 )
145 )
146 {
147 // Add-ref the Features that the user has specified
148 this->template visit_if<detail::contains_feature_of_<Features> >(
149 detail::make_add_ref_visitor(detail::accumulator_params()(*this))
150 );
151 }
152
153 /// \overload
154 ///
155 /// \param a1 Optional named parameter to be passed to all the accumulators
156 template<typename A1>
157 explicit accumulator_set(A1 const &a1)
158 : accumulators(
159 detail::make_acc_list(
160 accumulators_mpl_vector()
161 , detail::accumulator_params()(*this, a1)
162 )
163 )
164 {
165 // Add-ref the Features that the user has specified
166 this->template visit_if<detail::contains_feature_of_<Features> >(
167 detail::make_add_ref_visitor(detail::accumulator_params()(*this))
168 );
169 }
170
171 // ... other overloads generated by Boost.Preprocessor:
172
173 /// INTERNAL ONLY
174 ///
175#define BOOST_ACCUMULATORS_ACCUMULATOR_SET_CTOR(z, n, _) \
176 template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
177 accumulator_set(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a)) \
178 : accumulators( \
179 detail::make_acc_list( \
180 accumulators_mpl_vector() \
181 , detail::accumulator_params()( \
182 *this BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \
183 ) \
184 ) \
185 ) \
186 { \
187 /* Add-ref the Features that the user has specified */ \
188 this->template visit_if<detail::contains_feature_of_<Features> >( \
189 detail::make_add_ref_visitor(detail::accumulator_params()(*this)) \
190 ); \
191 }
192
193 /// INTERNAL ONLY
194 ///
195 BOOST_PP_REPEAT_FROM_TO(
196 2
197 , BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
198 , BOOST_ACCUMULATORS_ACCUMULATOR_SET_CTOR
199 , _
200 )
201
202 #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
203 /// \overload
204 ///
205 template<typename A1, typename A2, ...>
206 accumulator_set(A1 const &a1, A2 const &a2, ...);
207 #endif
208
209 // ... other overloads generated by Boost.Preprocessor below ...
210
211 ///////////////////////////////////////////////////////////////////////////////
212 /// Visitation
213 /// \param func UnaryFunction which is invoked with each accumulator in turn.
214 template<typename UnaryFunction>
215 void visit(UnaryFunction const &func)
216 {
217 fusion::for_each(this->accumulators, func);
218 }
219
220 ///////////////////////////////////////////////////////////////////////////////
221 /// Conditional visitation
222 /// \param func UnaryFunction which is invoked with each accumulator in turn,
223 /// provided the accumulator satisfies the MPL predicate FilterPred.
224 template<typename FilterPred, typename UnaryFunction>
225 void visit_if(UnaryFunction const &func)
226 {
227 fusion::filter_view<accumulators_type, FilterPred> filtered_accs(this->accumulators);
228 fusion::for_each(filtered_accs, func);
229 }
230
231 ///////////////////////////////////////////////////////////////////////////////
232 /// The return type of the operator() overloads is void.
233 typedef void result_type;
234
235 ///////////////////////////////////////////////////////////////////////////////
236 /// Accumulation
237 /// \param a1 Optional named parameter to be passed to all the accumulators
238 void operator ()()
239 {
240 this->visit(
241 detail::make_accumulator_visitor(
242 detail::accumulator_params()(*this)
243 )
244 );
245 }
246
247 template<typename A1>
248 void operator ()(A1 const &a1)
249 {
250 this->visit(
251 detail::make_accumulator_visitor(
252 detail::accumulator_params()(*this, a1)
253 )
254 );
255 }
256
257 // ... other overloads generated by Boost.Preprocessor:
258
259 /// INTERNAL ONLY
260 ///
261#define BOOST_ACCUMULATORS_ACCUMULATOR_SET_FUN_OP(z, n, _) \
262 template<BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
263 void operator ()(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, const &a)) \
264 { \
265 this->visit( \
266 detail::make_accumulator_visitor( \
267 detail::accumulator_params()( \
268 *this BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \
269 ) \
270 ) \
271 ); \
272 }
273
274 /// INTERNAL ONLY
275 ///
276 BOOST_PP_REPEAT_FROM_TO(
277 2
278 , BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
279 , BOOST_ACCUMULATORS_ACCUMULATOR_SET_FUN_OP
280 , _
281 )
282
283 #ifdef BOOST_ACCUMULATORS_DOXYGEN_INVOKED
284 /// \overload
285 ///
286 template<typename A1, typename A2, ...>
287 void operator ()(A1 const &a1, A2 const &a2, ...);
288 #endif
289
290 ///////////////////////////////////////////////////////////////////////////////
291 /// Extraction
292 template<typename Feature>
293 struct apply
294 : fusion::result_of::value_of<
295 typename fusion::result_of::find_if<
296 accumulators_type
297 , detail::matches_feature<Feature>
298 >::type
299 >
300 {
301 };
302
303 ///////////////////////////////////////////////////////////////////////////////
304 /// Extraction
305 template<typename Feature>
306 typename apply<Feature>::type &extract()
307 {
308 return *fusion::find_if<detail::matches_feature<Feature> >(this->accumulators);
309 }
310
311 /// \overload
312 template<typename Feature>
313 typename apply<Feature>::type const &extract() const
314 {
315 return *fusion::find_if<detail::matches_feature<Feature> >(this->accumulators);
316 }
317
318 ///////////////////////////////////////////////////////////////////////////////
319 /// Drop
320 template<typename Feature>
321 void drop()
322 {
323 // You can only drop the features that you have specified explicitly
324 typedef typename apply<Feature>::type the_accumulator;
325 BOOST_MPL_ASSERT((detail::contains_feature_of<Features, the_accumulator>));
326
327 typedef
328 typename feature_of<typename as_feature<Feature>::type>::type
329 the_feature;
330
331 (*fusion::find_if<detail::matches_feature<Feature> >(this->accumulators))
332 .drop(detail::accumulator_params()(*this));
333
334 // Also drop accumulators that this feature depends on
335 typedef typename the_feature::dependencies dependencies;
336 this->template visit_if<detail::contains_feature_of_<dependencies> >(
337 detail::make_drop_visitor(detail::accumulator_params()(*this))
338 );
339 }
340
341private:
342
343 accumulators_type accumulators;
344};
345
346#ifdef _MSC_VER
347#pragma warning(pop)
348#endif
349
350///////////////////////////////////////////////////////////////////////////////
351// find_accumulator
352// find an accumulator in an accumulator_set corresponding to a feature
353template<typename Feature, typename AccumulatorSet>
354typename mpl::apply<AccumulatorSet, Feature>::type &
355find_accumulator(AccumulatorSet &acc BOOST_ACCUMULATORS_PROTO_DISABLE_IF_IS_CONST(AccumulatorSet))
356{
357 return acc.template extract<Feature>();
358}
359
360/// \overload
361template<typename Feature, typename AccumulatorSet>
362typename mpl::apply<AccumulatorSet, Feature>::type const &
363find_accumulator(AccumulatorSet const &acc)
364{
365 return acc.template extract<Feature>();
366}
367
368///////////////////////////////////////////////////////////////////////////////
369// extract_result
370// extract a result from an accumulator set
371/// INTERNAL ONLY
372///
373#define BOOST_ACCUMULATORS_EXTRACT_RESULT_FUN(z, n, _) \
374 template< \
375 typename Feature \
376 , typename AccumulatorSet \
377 BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, typename A) \
378 > \
379 typename mpl::apply<AccumulatorSet, Feature>::type::result_type \
380 extract_result( \
381 AccumulatorSet const &acc \
382 BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(z, n, A, const &a) \
383 ) \
384 { \
385 return find_accumulator<Feature>(acc).result( \
386 detail::accumulator_params()( \
387 acc \
388 BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, a) \
389 ) \
390 ); \
391 }
392
393BOOST_PP_REPEAT(
394 BOOST_PP_INC(BOOST_ACCUMULATORS_MAX_ARGS)
395 , BOOST_ACCUMULATORS_EXTRACT_RESULT_FUN
396 , _
397)
398
399}} // namespace boost::accumulators
400
401#endif
402

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