while.hpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /*!
  2. @file
  3. Defines `boost::hana::while_`.
  4. @copyright Louis Dionne 2013-2017
  5. Distributed under the Boost Software License, Version 1.0.
  6. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  7. */
  8. #ifndef BOOST_HANA_WHILE_HPP
  9. #define BOOST_HANA_WHILE_HPP
  10. #include <boost/hana/fwd/while.hpp>
  11. #include <boost/hana/bool.hpp>
  12. #include <boost/hana/concept/constant.hpp>
  13. #include <boost/hana/concept/constant.hpp>
  14. #include <boost/hana/concept/logical.hpp>
  15. #include <boost/hana/config.hpp>
  16. #include <boost/hana/core/to.hpp>
  17. #include <boost/hana/core/dispatch.hpp>
  18. #include <boost/hana/detail/canonical_constant.hpp>
  19. #include <type_traits>
  20. BOOST_HANA_NAMESPACE_BEGIN
  21. //! @cond
  22. template <typename Pred, typename State, typename F>
  23. constexpr decltype(auto) while_t::operator()(Pred&& pred, State&& state, F&& f) const {
  24. using Cond = decltype(pred(state));
  25. using Bool = typename hana::tag_of<Cond>::type;
  26. using While = BOOST_HANA_DISPATCH_IF(while_impl<Bool>,
  27. hana::Logical<Bool>::value
  28. );
  29. #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
  30. static_assert(hana::Logical<Bool>::value,
  31. "hana::while_(pred, state, f) requires 'pred(state)' to be a Logical");
  32. #endif
  33. return While::apply(static_cast<Pred&&>(pred),
  34. static_cast<State&&>(state),
  35. static_cast<F&&>(f));
  36. }
  37. //! @endcond
  38. template <typename L, bool condition>
  39. struct while_impl<L, hana::when<condition>> : hana::default_ {
  40. template <typename ...Args>
  41. static constexpr auto apply(Args&& ...) = delete;
  42. };
  43. template <typename L>
  44. struct while_impl<L, hana::when<std::is_arithmetic<L>::value>> {
  45. template <typename Pred, typename State, typename F>
  46. static auto apply(Pred&& pred, State&& state, F&& f)
  47. -> decltype(
  48. true ? f(static_cast<State&&>(state))
  49. : static_cast<State&&>(state)
  50. )
  51. {
  52. if (pred(state)) {
  53. decltype(auto) r = f(static_cast<State&&>(state));
  54. return hana::while_(static_cast<Pred&&>(pred),
  55. static_cast<decltype(r)&&>(r),
  56. static_cast<F&&>(f));
  57. }
  58. else {
  59. return static_cast<State&&>(state);
  60. }
  61. }
  62. };
  63. template <typename C>
  64. struct while_impl<C, hana::when<
  65. hana::Constant<C>::value &&
  66. hana::Logical<typename C::value_type>::value
  67. >> {
  68. template <typename Pred, typename State, typename F>
  69. static constexpr State
  70. while_helper(hana::false_, Pred&&, State&& state, F&&) {
  71. return static_cast<State&&>(state);
  72. }
  73. template <typename Pred, typename State, typename F>
  74. static constexpr decltype(auto)
  75. while_helper(hana::true_, Pred&& pred, State&& state, F&& f) {
  76. decltype(auto) r = f(static_cast<State&&>(state));
  77. return hana::while_(static_cast<Pred&&>(pred),
  78. static_cast<decltype(r)&&>(r),
  79. static_cast<F&&>(f));
  80. }
  81. template <typename Pred, typename State, typename F>
  82. static constexpr decltype(auto)
  83. apply(Pred&& pred, State&& state, F&& f) {
  84. // Since `pred(state)` returns a `Constant`, we do not actually
  85. // need to call it; we only need its decltype. However, we still
  86. // call it to run potential side effects. I'm not sure whether
  87. // that is desirable, since we pretty much take for granted that
  88. // functions are pure, but we'll do it like this for now. Also, I
  89. // think there is something rather deep hidden behind this, and
  90. // understanding what must be done here should give us a better
  91. // understanding of something non-trivial.
  92. auto cond_ = pred(state);
  93. constexpr auto cond = hana::value(cond_);
  94. constexpr bool truth_value = hana::if_(cond, true, false);
  95. return while_helper(hana::bool_c<truth_value>,
  96. static_cast<Pred&&>(pred),
  97. static_cast<State&&>(state),
  98. static_cast<F&&>(f));
  99. }
  100. };
  101. BOOST_HANA_NAMESPACE_END
  102. #endif // !BOOST_HANA_WHILE_HPP