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