iterate.hpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*!
  2. @file
  3. Defines `boost::hana::iterate`.
  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_FUNCTIONAL_ITERATE_HPP
  9. #define BOOST_HANA_FUNCTIONAL_ITERATE_HPP
  10. #include <boost/hana/config.hpp>
  11. #include <boost/hana/core/when.hpp>
  12. #include <boost/hana/functional/partial.hpp>
  13. #include <cstddef>
  14. BOOST_HANA_NAMESPACE_BEGIN
  15. //! @ingroup group-functional
  16. //! Applies another function `n` times to its argument.
  17. //!
  18. //! Given a function `f` and an argument `x`, `iterate<n>(f, x)` returns
  19. //! the result of applying `f` `n` times to its argument. In other words,
  20. //! @code
  21. //! iterate<n>(f, x) == f(f( ... f(x)))
  22. //! ^^^^^^^^^^ n times total
  23. //! @endcode
  24. //!
  25. //! If `n == 0`, `iterate<n>(f, x)` returns the `x` argument unchanged
  26. //! and `f` is never applied. It is important to note that the function
  27. //! passed to `iterate<n>` must be a unary function. Indeed, since `f`
  28. //! will be called with the result of the previous `f` application, it
  29. //! may only take a single argument.
  30. //!
  31. //! In addition to what's documented above, `iterate` can also be
  32. //! partially applied to the function argument out-of-the-box. In
  33. //! other words, `iterate<n>(f)` is a function object applying `f`
  34. //! `n` times to the argument it is called with, which means that
  35. //! @code
  36. //! iterate<n>(f)(x) == iterate<n>(f, x)
  37. //! @endcode
  38. //!
  39. //! This is provided for convenience, and it turns out to be especially
  40. //! useful in conjunction with higher-order algorithms.
  41. //!
  42. //!
  43. //! Signature
  44. //! ---------
  45. //! Given a function \f$ f : T \to T \f$ and `x` and argument of data
  46. //! type `T`, the signature is
  47. //! \f$
  48. //! \mathtt{iterate_n} : (T \to T) \times T \to T
  49. //! \f$
  50. //!
  51. //! @tparam n
  52. //! An unsigned integer representing the number of times that `f`
  53. //! should be applied to its argument.
  54. //!
  55. //! @param f
  56. //! A function to apply `n` times to its argument.
  57. //!
  58. //! @param x
  59. //! The initial value to call `f` with.
  60. //!
  61. //!
  62. //! Example
  63. //! -------
  64. //! @include example/functional/iterate.cpp
  65. #ifdef BOOST_HANA_DOXYGEN_INVOKED
  66. template <std::size_t n>
  67. constexpr auto iterate = [](auto&& f) {
  68. return [perfect-capture](auto&& x) -> decltype(auto) {
  69. return f(f( ... f(forwarded(x))));
  70. };
  71. };
  72. #else
  73. template <std::size_t n, typename = when<true>>
  74. struct iterate_t;
  75. template <>
  76. struct iterate_t<0> {
  77. template <typename F, typename X>
  78. constexpr X operator()(F&&, X&& x) const
  79. { return static_cast<X&&>(x); }
  80. };
  81. template <>
  82. struct iterate_t<1> {
  83. template <typename F, typename X>
  84. constexpr decltype(auto) operator()(F&& f, X&& x) const {
  85. return f(static_cast<X&&>(x));
  86. }
  87. };
  88. template <>
  89. struct iterate_t<2> {
  90. template <typename F, typename X>
  91. constexpr decltype(auto) operator()(F&& f, X&& x) const {
  92. return f(f(static_cast<X&&>(x)));
  93. }
  94. };
  95. template <>
  96. struct iterate_t<3> {
  97. template <typename F, typename X>
  98. constexpr decltype(auto) operator()(F&& f, X&& x) const {
  99. return f(f(f(static_cast<X&&>(x))));
  100. }
  101. };
  102. template <>
  103. struct iterate_t<4> {
  104. template <typename F, typename X>
  105. constexpr decltype(auto) operator()(F&& f, X&& x) const {
  106. return f(f(f(f(static_cast<X&&>(x)))));
  107. }
  108. };
  109. template <>
  110. struct iterate_t<5> {
  111. template <typename F, typename X>
  112. constexpr decltype(auto) operator()(F&& f, X&& x) const {
  113. return f(f(f(f(f(static_cast<X&&>(x))))));
  114. }
  115. };
  116. template <std::size_t n>
  117. struct iterate_t<n, when<(n >= 6) && (n < 12)>> {
  118. template <typename F, typename X>
  119. constexpr decltype(auto) operator()(F&& f, X&& x) const {
  120. return iterate_t<n - 6>{}(f,
  121. f(f(f(f(f(f(static_cast<X&&>(x)))))))
  122. );
  123. }
  124. };
  125. template <std::size_t n>
  126. struct iterate_t<n, when<(n >= 12) && (n < 24)>> {
  127. template <typename F, typename X>
  128. constexpr decltype(auto) operator()(F&& f, X&& x) const {
  129. return iterate_t<n - 12>{}(f,
  130. f(f(f(f(f(f(f(f(f(f(f(f(
  131. static_cast<X&&>(x)
  132. ))))))))))))
  133. );
  134. }
  135. };
  136. template <std::size_t n>
  137. struct iterate_t<n, when<(n >= 24) && (n < 48)>> {
  138. template <typename F, typename X>
  139. constexpr decltype(auto) operator()(F&& f, X&& x) const {
  140. return iterate_t<n - 24>{}(f,
  141. f(f(f(f(f(f(f(f(f(f(f(f(
  142. f(f(f(f(f(f(f(f(f(f(f(f(
  143. static_cast<X&&>(x)
  144. ))))))))))))
  145. ))))))))))))
  146. );
  147. }
  148. };
  149. template <std::size_t n>
  150. struct iterate_t<n, when<(n >= 48)>> {
  151. template <typename F, typename X>
  152. constexpr decltype(auto) operator()(F&& f, X&& x) const {
  153. return iterate_t<n - 48>{}(f,
  154. f(f(f(f(f(f(f(f(f(f(f(f(
  155. f(f(f(f(f(f(f(f(f(f(f(f(
  156. f(f(f(f(f(f(f(f(f(f(f(f(
  157. f(f(f(f(f(f(f(f(f(f(f(f(
  158. static_cast<X&&>(x)
  159. ))))))))))))
  160. ))))))))))))
  161. ))))))))))))
  162. ))))))))))))
  163. );
  164. }
  165. };
  166. template <std::size_t n>
  167. struct make_iterate_t {
  168. template <typename F>
  169. constexpr decltype(auto) operator()(F&& f) const
  170. { return hana::partial(iterate_t<n>{}, static_cast<F&&>(f)); }
  171. template <typename F, typename X>
  172. constexpr decltype(auto) operator()(F&& f, X&& x) const {
  173. return iterate_t<n>{}(static_cast<F&&>(f),
  174. static_cast<X&&>(x));
  175. }
  176. };
  177. template <std::size_t n>
  178. constexpr make_iterate_t<n> iterate{};
  179. #endif
  180. BOOST_HANA_NAMESPACE_END
  181. #endif // !BOOST_HANA_FUNCTIONAL_ITERATE_HPP