repeat_while.hpp 5.0 KB

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