accumulator_set.hpp 23 KB

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