accumulator_set.hpp 23 KB

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