diff options
Diffstat (limited to 'boost/hana/functional/iterate.hpp')
-rw-r--r-- | boost/hana/functional/iterate.hpp | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/boost/hana/functional/iterate.hpp b/boost/hana/functional/iterate.hpp new file mode 100644 index 0000000000..b2ec27f5ec --- /dev/null +++ b/boost/hana/functional/iterate.hpp @@ -0,0 +1,201 @@ +/*! +@file +Defines `boost::hana::iterate`. + +@copyright Louis Dionne 2013-2016 +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 <boost/hana/config.hpp> +#include <boost/hana/core/when.hpp> +#include <boost/hana/functional/partial.hpp> + +#include <cstddef> + + +BOOST_HANA_NAMESPACE_BEGIN + //! @ingroup group-functional + //! Applies another function `n` times to its argument. + //! + //! Given a function `f` and an argument `x`, `iterate<n>(f, x)` returns + //! the result of applying `f` `n` times to its argument. In other words, + //! @code + //! iterate<n>(f, x) == f(f( ... f(x))) + //! ^^^^^^^^^^ n times total + //! @endcode + //! + //! If `n == 0`, `iterate<n>(f, x)` returns the `x` argument unchanged + //! and `f` is never applied. It is important to note that the function + //! passed to `iterate<n>` 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<n>(f)` is a function object applying `f` + //! `n` times to the argument it is called with, which means that + //! @code + //! iterate<n>(f)(x) == iterate<n>(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 <std::size_t n> + constexpr auto iterate = [](auto&& f) { + return [perfect-capture](auto&& x) -> decltype(auto) { + return f(f( ... f(forwarded(x)))); + }; + }; +#else + template <std::size_t n, typename = when<true>> + struct iterate_t; + + template <> + struct iterate_t<0> { + template <typename F, typename X> + constexpr X operator()(F&&, X&& x) const + { return static_cast<X&&>(x); } + }; + + template <> + struct iterate_t<1> { + template <typename F, typename X> + constexpr decltype(auto) operator()(F&& f, X&& x) const { + return f(static_cast<X&&>(x)); + } + }; + + template <> + struct iterate_t<2> { + template <typename F, typename X> + constexpr decltype(auto) operator()(F&& f, X&& x) const { + return f(f(static_cast<X&&>(x))); + } + }; + + template <> + struct iterate_t<3> { + template <typename F, typename X> + constexpr decltype(auto) operator()(F&& f, X&& x) const { + return f(f(f(static_cast<X&&>(x)))); + } + }; + + template <> + struct iterate_t<4> { + template <typename F, typename X> + constexpr decltype(auto) operator()(F&& f, X&& x) const { + return f(f(f(f(static_cast<X&&>(x))))); + } + }; + + template <> + struct iterate_t<5> { + template <typename F, typename X> + constexpr decltype(auto) operator()(F&& f, X&& x) const { + return f(f(f(f(f(static_cast<X&&>(x)))))); + } + }; + + template <std::size_t n> + struct iterate_t<n, when<(n >= 6) && (n < 12)>> { + template <typename F, typename X> + constexpr decltype(auto) operator()(F&& f, X&& x) const { + return iterate_t<n - 6>{}(f, + f(f(f(f(f(f(static_cast<X&&>(x))))))) + ); + } + }; + + template <std::size_t n> + struct iterate_t<n, when<(n >= 12) && (n < 24)>> { + template <typename F, typename X> + constexpr decltype(auto) operator()(F&& f, X&& x) const { + return iterate_t<n - 12>{}(f, + f(f(f(f(f(f(f(f(f(f(f(f( + static_cast<X&&>(x) + )))))))))))) + ); + } + }; + + template <std::size_t n> + struct iterate_t<n, when<(n >= 24) && (n < 48)>> { + template <typename F, typename X> + constexpr decltype(auto) operator()(F&& f, X&& x) const { + return iterate_t<n - 24>{}(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&&>(x) + )))))))))))) + )))))))))))) + ); + } + }; + + template <std::size_t n> + struct iterate_t<n, when<(n >= 48)>> { + template <typename F, typename X> + constexpr decltype(auto) operator()(F&& f, X&& x) const { + return iterate_t<n - 48>{}(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&&>(x) + )))))))))))) + )))))))))))) + )))))))))))) + )))))))))))) + ); + } + }; + + template <std::size_t n> + struct make_iterate_t { + template <typename F> + constexpr decltype(auto) operator()(F&& f) const + { return hana::partial(iterate_t<n>{}, static_cast<F&&>(f)); } + + template <typename F, typename X> + constexpr decltype(auto) operator()(F&& f, X&& x) const { + return iterate_t<n>{}(static_cast<F&&>(f), + static_cast<X&&>(x)); + } + }; + + template <std::size_t n> + constexpr make_iterate_t<n> iterate{}; +#endif +BOOST_HANA_NAMESPACE_END + +#endif // !BOOST_HANA_FUNCTIONAL_ITERATE_HPP |