• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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