• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*=============================================================================
2    Copyright (c) 2015 Paul Fultz II
3    repeat.h
4    Distributed under the Boost Software License, Version 1.0. (See accompanying
5    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6==============================================================================*/
7
8#ifndef BOOST_HOF_GUARD_REPEAT_H
9#define BOOST_HOF_GUARD_REPEAT_H
10
11/// repeat
12/// ======
13///
14/// Description
15/// -----------
16///
17/// The `repeat` function decorator will repeatedly apply a function a given
18/// number of times.
19///
20///
21/// Synopsis
22/// --------
23///
24///     template<class Integral>
25///     constexpr auto repeat(Integral);
26///
27/// Semantics
28/// ---------
29///
30///     assert(repeat(std::integral_constant<int, 0>{})(f)(xs...) == f(xs...));
31///     assert(repeat(std::integral_constant<int, 1>{})(f)(xs...) == f(f(xs...)));
32///     assert(repeat(0)(f)(xs...) == f(xs...));
33///     assert(repeat(1)(f)(xs...) == f(f(xs...)));
34///
35/// Requirements
36/// ------------
37///
38/// Integral must be:
39///
40/// * Integral
41///
42/// Or:
43///
44/// * IntegralConstant
45///
46/// Example
47/// -------
48///
49///     #include <boost/hof.hpp>
50///     #include <cassert>
51///
52///     struct increment
53///     {
54///         template<class T>
55///         constexpr T operator()(T x) const
56///         {
57///             return x + 1;
58///         }
59///     };
60///
61///     int main() {
62///         auto increment_by_5 = boost::hof::repeat(std::integral_constant<int, 5>())(increment());
63///         assert(increment_by_5(1) == 6);
64///     }
65///
66
67#include <boost/hof/always.hpp>
68#include <boost/hof/detail/delegate.hpp>
69#include <boost/hof/detail/result_of.hpp>
70#include <boost/hof/detail/move.hpp>
71#include <boost/hof/detail/static_const_var.hpp>
72#include <boost/hof/decorate.hpp>
73#include <boost/hof/first_of.hpp>
74#include <boost/hof/detail/recursive_constexpr_depth.hpp>
75
76namespace boost { namespace hof { namespace detail {
77
78template<int N>
79struct repeater
80{
81    template<class F, class... Ts>
82    constexpr BOOST_HOF_SFINAE_RESULT(repeater<N-1>, id_<const F&>, result_of<const F&, id_<Ts>...>)
83    operator()(const F& f, Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS
84    (
85        repeater<N-1>()(f, f(BOOST_HOF_FORWARD(Ts)(xs)...))
86    );
87};
88
89template<>
90struct repeater<0>
91{
92    template<class F, class T>
93    constexpr T operator()(const F&, T&& x) const
94    BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(T(x))
95    {
96        return x;
97    }
98};
99
100struct repeat_constant_decorator
101{
102    template<class Integral, class F, class... Ts>
103    constexpr auto operator()(Integral, const F& f, Ts&&... xs) const BOOST_HOF_RETURNS
104    (
105        detail::repeater<Integral::type::value>()
106        (
107            f,
108            BOOST_HOF_FORWARD(Ts)(xs)...
109        )
110    );
111};
112
113template<int Depth>
114struct repeat_integral_decorator
115{
116    template<class Integral, class F, class T, class... Ts, class Self=repeat_integral_decorator<Depth-1>>
117    constexpr auto operator()(Integral n, const F& f, T&& x, Ts&&... xs) const BOOST_HOF_RETURNS
118    (
119        (n) ?
120            Self()(n-1, f, f(BOOST_HOF_FORWARD(T)(x), BOOST_HOF_FORWARD(Ts)(xs)...)) :
121            BOOST_HOF_FORWARD(T)(x)
122    );
123};
124
125template<>
126struct repeat_integral_decorator<0>
127{
128    template<class Integral, class F, class T, class Self=repeat_integral_decorator<0>>
129#if BOOST_HOF_HAS_RELAXED_CONSTEXPR
130    constexpr
131#endif
132    auto operator()(Integral n, const F& f, T x) const
133    BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT((n--, f(BOOST_HOF_FORWARD(T)(x))))
134    -> decltype(f(BOOST_HOF_FORWARD(T)(x)))
135    {
136        while(n > 0)
137        {
138            n--;
139            x = f(BOOST_HOF_FORWARD(T)(x));
140        }
141        return x;
142    }
143    // TODO: Add overload for lvalue
144};
145
146}
147
148#if BOOST_HOF_HAS_RELAXED_CONSTEXPR
149#define BOOST_HOF_REPEAT_CONSTEXPR_DEPTH 1
150#else
151#define BOOST_HOF_REPEAT_CONSTEXPR_DEPTH BOOST_HOF_RECURSIVE_CONSTEXPR_DEPTH
152#endif
153
154BOOST_HOF_DECLARE_STATIC_VAR(repeat, decorate_adaptor<
155    boost::hof::first_of_adaptor<
156    detail::repeat_constant_decorator,
157    detail::repeat_integral_decorator<BOOST_HOF_REPEAT_CONSTEXPR_DEPTH>
158>>);
159
160}} // namespace boost::hof
161
162#endif
163