summaryrefslogtreecommitdiff
path: root/boost/hana/functional/iterate.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/hana/functional/iterate.hpp')
-rw-r--r--boost/hana/functional/iterate.hpp201
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