• 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 
76 namespace boost { namespace hof { namespace detail {
77 
78 template<int N>
79 struct 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 
89 template<>
90 struct repeater<0>
91 {
92     template<class F, class T>
operator ()boost::hof::detail::repeater93     constexpr T operator()(const F&, T&& x) const
94     BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(T(x))
95     {
96         return x;
97     }
98 };
99 
100 struct 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 
113 template<int Depth>
114 struct 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 
125 template<>
126 struct 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
operator ()boost::hof::detail::repeat_integral_decorator132     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 
154 BOOST_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