/*! @file Defines `boost::hana::iterate`. @copyright Louis Dionne 2013-2017 Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) */ #ifndef BOOST_HANA_FUNCTIONAL_ITERATE_HPP #define BOOST_HANA_FUNCTIONAL_ITERATE_HPP #include #include #include #include namespace boost { namespace hana { //! @ingroup group-functional //! Applies another function `n` times to its argument. //! //! Given a function `f` and an argument `x`, `iterate(f, x)` returns //! the result of applying `f` `n` times to its argument. In other words, //! @code //! iterate(f, x) == f(f( ... f(x))) //! ^^^^^^^^^^ n times total //! @endcode //! //! If `n == 0`, `iterate(f, x)` returns the `x` argument unchanged //! and `f` is never applied. It is important to note that the function //! passed to `iterate` must be a unary function. Indeed, since `f` //! will be called with the result of the previous `f` application, it //! may only take a single argument. //! //! In addition to what's documented above, `iterate` can also be //! partially applied to the function argument out-of-the-box. In //! other words, `iterate(f)` is a function object applying `f` //! `n` times to the argument it is called with, which means that //! @code //! iterate(f)(x) == iterate(f, x) //! @endcode //! //! This is provided for convenience, and it turns out to be especially //! useful in conjunction with higher-order algorithms. //! //! //! Signature //! --------- //! Given a function \f$ f : T \to T \f$ and `x` and argument of data //! type `T`, the signature is //! \f$ //! \mathtt{iterate_n} : (T \to T) \times T \to T //! \f$ //! //! @tparam n //! An unsigned integer representing the number of times that `f` //! should be applied to its argument. //! //! @param f //! A function to apply `n` times to its argument. //! //! @param x //! The initial value to call `f` with. //! //! //! Example //! ------- //! @include example/functional/iterate.cpp #ifdef BOOST_HANA_DOXYGEN_INVOKED template constexpr auto iterate = [](auto&& f) { return [perfect-capture](auto&& x) -> decltype(auto) { return f(f( ... f(forwarded(x)))); }; }; #else template > struct iterate_t; template <> struct iterate_t<0> { template constexpr X operator()(F&&, X&& x) const { return static_cast(x); } }; template <> struct iterate_t<1> { template constexpr decltype(auto) operator()(F&& f, X&& x) const { return f(static_cast(x)); } }; template <> struct iterate_t<2> { template constexpr decltype(auto) operator()(F&& f, X&& x) const { return f(f(static_cast(x))); } }; template <> struct iterate_t<3> { template constexpr decltype(auto) operator()(F&& f, X&& x) const { return f(f(f(static_cast(x)))); } }; template <> struct iterate_t<4> { template constexpr decltype(auto) operator()(F&& f, X&& x) const { return f(f(f(f(static_cast(x))))); } }; template <> struct iterate_t<5> { template constexpr decltype(auto) operator()(F&& f, X&& x) const { return f(f(f(f(f(static_cast(x)))))); } }; template struct iterate_t= 6) && (n < 12)>> { template constexpr decltype(auto) operator()(F&& f, X&& x) const { return iterate_t{}(f, f(f(f(f(f(f(static_cast(x))))))) ); } }; template struct iterate_t= 12) && (n < 24)>> { template constexpr decltype(auto) operator()(F&& f, X&& x) const { return iterate_t{}(f, f(f(f(f(f(f(f(f(f(f(f(f( static_cast(x) )))))))))))) ); } }; template struct iterate_t= 24) && (n < 48)>> { template constexpr decltype(auto) operator()(F&& f, X&& x) const { return iterate_t{}(f, f(f(f(f(f(f(f(f(f(f(f(f( f(f(f(f(f(f(f(f(f(f(f(f( static_cast(x) )))))))))))) )))))))))))) ); } }; template struct iterate_t= 48)>> { template constexpr decltype(auto) operator()(F&& f, X&& x) const { return iterate_t{}(f, f(f(f(f(f(f(f(f(f(f(f(f( f(f(f(f(f(f(f(f(f(f(f(f( f(f(f(f(f(f(f(f(f(f(f(f( f(f(f(f(f(f(f(f(f(f(f(f( static_cast(x) )))))))))))) )))))))))))) )))))))))))) )))))))))))) ); } }; template struct make_iterate_t { template constexpr decltype(auto) operator()(F&& f) const { return hana::partial(iterate_t{}, static_cast(f)); } template constexpr decltype(auto) operator()(F&& f, X&& x) const { return iterate_t{}(static_cast(f), static_cast(x)); } }; template BOOST_HANA_INLINE_VARIABLE constexpr make_iterate_t iterate{}; #endif }} // end namespace boost::hana #endif // !BOOST_HANA_FUNCTIONAL_ITERATE_HPP