1/*============================================================================= 2 Copyright (c) 2015 Paul Fultz II 3 repeat_while.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_WHILE_H 9#define BOOST_HOF_GUARD_REPEAT_WHILE_H 10 11/// repeat_while 12/// ====== 13/// 14/// Description 15/// ----------- 16/// 17/// The `repeat_while` function decorator will repeatedly apply a function while 18/// the predicate returns a boolean that is true. If the predicate returns an 19/// `IntergralConstant` then the predicate is only evaluated at compile-time. 20/// 21/// 22/// Synopsis 23/// -------- 24/// 25/// template<class Predicate> 26/// constexpr auto repeat_while(Predicate predicate); 27/// 28/// Requirements 29/// ------------ 30/// 31/// Predicate must be: 32/// 33/// * [ConstFunctionObject](ConstFunctionObject) 34/// * MoveConstructible 35/// 36/// Example 37/// ------- 38/// 39/// #include <boost/hof.hpp> 40/// #include <cassert> 41/// 42/// struct increment 43/// { 44/// template<class T> 45/// constexpr std::integral_constant<int, T::value + 1> operator()(T) const 46/// { 47/// return std::integral_constant<int, T::value + 1>(); 48/// } 49/// }; 50/// 51/// struct not_6 52/// { 53/// template<class T> 54/// constexpr std::integral_constant<bool, (T::value != 6)> 55/// operator()(T) const 56/// { 57/// return std::integral_constant<bool, (T::value != 6)>(); 58/// } 59/// }; 60/// 61/// typedef std::integral_constant<int, 1> one; 62/// typedef std::integral_constant<int, 6> six; 63/// 64/// int main() { 65/// auto increment_until_6 = boost::hof::repeat_while(not_6())(increment()); 66/// static_assert(std::is_same<six, decltype(increment_until_6(one()))>::value, "Error"); 67/// } 68/// 69 70#include <boost/hof/always.hpp> 71#include <boost/hof/detail/delegate.hpp> 72#include <boost/hof/detail/result_of.hpp> 73#include <boost/hof/detail/move.hpp> 74#include <boost/hof/decorate.hpp> 75#include <boost/hof/detail/static_const_var.hpp> 76#include <boost/hof/first_of.hpp> 77#include <boost/hof/detail/recursive_constexpr_depth.hpp> 78 79namespace boost { namespace hof { namespace detail { 80 81template<class P, class... Ts> 82struct compute_predicate 83{ 84 typedef decltype(std::declval<P>()(std::declval<Ts>()...)) type; 85}; 86 87template<bool B> 88struct while_repeater 89{ 90 template<class F, class P, class... Ts> 91 constexpr BOOST_HOF_SFINAE_RESULT(while_repeater< 92 compute_predicate<P, typename result_of<const F&, id_<Ts>...>::type>::type::value 93 >, id_<const F&>, id_<const P&>, result_of<const F&, id_<Ts>...>) 94 operator()(const F& f, const P& p, Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS 95 ( 96 while_repeater< 97 compute_predicate<P, decltype(f(BOOST_HOF_FORWARD(Ts)(xs)...))>::type::value 98 >()(f, p, f(BOOST_HOF_FORWARD(Ts)(xs)...)) 99 ); 100}; 101 102template<> 103struct while_repeater<false> 104{ 105 template<class F, class P, class T> 106 constexpr T operator()(const F&, const P&, T&& x) const 107 BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(x) 108 { 109 return x; 110 } 111}; 112 113struct repeat_while_constant_decorator 114{ 115 template<class P, class F, class... Ts> 116 constexpr auto operator()(const P& p, const F& f, Ts&&... xs) const BOOST_HOF_RETURNS 117 ( 118 detail::while_repeater< 119 detail::compute_predicate<P, decltype(std::declval<F>()(BOOST_HOF_FORWARD(Ts)(xs)...))>::type::value 120 >() 121 ( 122 f, 123 p, 124 BOOST_HOF_FORWARD(Ts)(xs)... 125 ) 126 ); 127}; 128 129template<int Depth> 130struct repeat_while_integral_decorator 131{ 132 template<class P, class F, class T, class... Ts, class Self=repeat_while_integral_decorator<Depth-1>> 133 constexpr auto operator()(const P& p, const F& f, T&& x, Ts&&... xs) const BOOST_HOF_RETURNS 134 ( 135 (p(x, BOOST_HOF_FORWARD(Ts)(xs)...)) ? 136 Self()( 137 p, 138 f, 139 f(x, BOOST_HOF_FORWARD(Ts)(xs)...) 140 ) : 141 BOOST_HOF_FORWARD(T)(x) 142 ); 143}; 144 145template<> 146struct repeat_while_integral_decorator<0> 147{ 148 template<class P, class F, class T, class Self=repeat_while_integral_decorator<0>> 149#if BOOST_HOF_HAS_RELAXED_CONSTEXPR 150 constexpr 151#endif 152 auto operator()(const P& p, const F& f, T x) const 153 BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT((p(x), f(x))) 154 -> decltype(f(x)) 155 { 156 while(p(x)) 157 { 158 // TODO: Should move? 159 x = f(x); 160 } 161 return x; 162 } 163}; 164} 165 166#if BOOST_HOF_HAS_RELAXED_CONSTEXPR 167#define BOOST_HOF_REPEAT_WHILE_CONSTEXPR_DEPTH 1 168#else 169#define BOOST_HOF_REPEAT_WHILE_CONSTEXPR_DEPTH BOOST_HOF_RECURSIVE_CONSTEXPR_DEPTH 170#endif 171 172BOOST_HOF_DECLARE_STATIC_VAR(repeat_while, decorate_adaptor< 173 boost::hof::first_of_adaptor< 174 detail::repeat_while_constant_decorator, 175 detail::repeat_while_integral_decorator<BOOST_HOF_REPEAT_WHILE_CONSTEXPR_DEPTH> 176 > 177>); 178 179}} // namespace boost::hof 180 181#endif 182