202 lines
6.3 KiB
C++
202 lines
6.3 KiB
C++
/*!
|
|
@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
|