1 /*=============================================================================
2     Copyright (c) 2015 Paul Fultz II
3     reverse_fold.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_REVERSE_FOLD_H
9 #define BOOST_HOF_GUARD_REVERSE_FOLD_H
10 
11 /// reverse_fold
12 /// ========
13 ///
14 /// Description
15 /// -----------
16 ///
17 /// The `reverse_fold` function adaptor uses a binary function to apply a
18 /// reverse [fold]
19 /// (https://en.wikipedia.org/wiki/Fold_%28higher-order_function%29)(ie right
20 /// fold in functional programming terms) operation to the arguments passed to
21 /// the function. Additionally, an optional initial state can be provided,
22 /// otherwise the first argument is used as the initial state.
23 ///
24 /// The arguments to the binary function, take first the state and then the
25 /// argument.
26 ///
27 /// Synopsis
28 /// --------
29 ///
30 ///     template<class F, class State>
31 ///     constexpr reverse_fold_adaptor<F, State> reverse_fold(F f, State s);
32 ///
33 ///     template<class F>
34 ///     constexpr reverse_fold_adaptor<F> reverse_fold(F f);
35 ///
36 /// Semantics
37 /// ---------
38 ///
39 ///     assert(reverse_fold(f, z)() == z);
40 ///     assert(reverse_fold(f, z)(x, xs...) == f(reverse_fold(f, z)(xs...), x));
41 ///     assert(reverse_fold(f)(x) == x);
42 ///     assert(reverse_fold(f)(x, xs...) == f(reverse_fold(f)(xs...), x));
43 ///
44 /// Requirements
45 /// ------------
46 ///
47 /// State must be:
48 ///
49 /// * CopyConstructible
50 ///
51 /// F must be:
52 ///
53 /// * [BinaryInvocable](BinaryInvocable)
54 /// * MoveConstructible
55 ///
56 /// Example
57 /// -------
58 ///
59 ///     #include <boost/hof.hpp>
60 ///     #include <cassert>
61 ///
62 ///     struct max_f
63 ///     {
64 ///         template<class T, class U>
65 ///         constexpr T operator()(T x, U y) const
66 ///         {
67 ///             return x > y ? x : y;
68 ///         }
69 ///     };
70 ///
71 ///     int main() {
72 ///         assert(boost::hof::reverse_fold(max_f())(2, 3, 4, 5) == 5);
73 ///     }
74 ///
75 /// References
76 /// ----------
77 ///
78 /// * [Projections](Projections)
79 /// * [Variadic print](<Variadic print>)
80 ///
81 
82 #include <boost/hof/detail/callable_base.hpp>
83 #include <boost/hof/detail/delegate.hpp>
84 #include <boost/hof/detail/compressed_pair.hpp>
85 #include <boost/hof/detail/move.hpp>
86 #include <boost/hof/detail/make.hpp>
87 #include <boost/hof/detail/static_const_var.hpp>
88 
89 namespace boost { namespace hof { namespace detail {
90 
91 struct v_reverse_fold
92 {
93     BOOST_HOF_RETURNS_CLASS(v_reverse_fold);
94     template<class F, class State, class T, class... Ts>
95     constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(const F&, result_of<const v_reverse_fold&, id_<const F&>, id_<State>, id_<Ts>...>, id_<T>)
96     operator()(const F& f, State&& state, T&& x, Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS
97     (
98         f((*BOOST_HOF_CONST_THIS)(f, BOOST_HOF_FORWARD(State)(state), BOOST_HOF_FORWARD(Ts)(xs)...), BOOST_HOF_FORWARD(T)(x))
99     );
100 
101     template<class F, class State>
operator ()boost::hof::detail::v_reverse_fold102     constexpr State operator()(const F&, State&& state) const noexcept
103     {
104         return BOOST_HOF_FORWARD(State)(state);
105     }
106 };
107 
108 }
109 
110 template<class F, class State=void>
111 struct reverse_fold_adaptor
112 : detail::compressed_pair<detail::callable_base<F>, State>
113 {
114     typedef detail::compressed_pair<detail::callable_base<F>, State> base_type;
BOOST_HOF_INHERIT_CONSTRUCTORboost::hof::reverse_fold_adaptor115     BOOST_HOF_INHERIT_CONSTRUCTOR(reverse_fold_adaptor, base_type)
116 
117     template<class... Ts>
118     constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const noexcept
119     {
120         return this->first(xs...);
121     }
122 
123     template<class... Ts>
get_stateboost::hof::reverse_fold_adaptor124     constexpr State get_state(Ts&&... xs) const noexcept
125     {
126         return this->second(xs...);
127     }
128 
129     BOOST_HOF_RETURNS_CLASS(reverse_fold_adaptor);
130 
131     template<class... Ts>
132     constexpr BOOST_HOF_SFINAE_RESULT(detail::v_reverse_fold, id_<const detail::callable_base<F>&>, id_<State>, id_<Ts>...)
133     operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS
134     (
135         detail::v_reverse_fold()(
136             BOOST_HOF_MANGLE_CAST(const detail::callable_base<F>&)(BOOST_HOF_CONST_THIS->base_function(xs...)),
137             BOOST_HOF_MANGLE_CAST(State)(BOOST_HOF_CONST_THIS->get_state(xs...)),
138             BOOST_HOF_FORWARD(Ts)(xs)...
139         )
140     )
141 };
142 
143 
144 template<class F>
145 struct reverse_fold_adaptor<F, void>
146 : detail::callable_base<F>
147 {
BOOST_HOF_INHERIT_CONSTRUCTORboost::hof::reverse_fold_adaptor148     BOOST_HOF_INHERIT_CONSTRUCTOR(reverse_fold_adaptor, detail::callable_base<F>)
149 
150     template<class... Ts>
151     constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const noexcept
152     {
153         return boost::hof::always_ref(*this)(xs...);
154     }
155 
156     BOOST_HOF_RETURNS_CLASS(reverse_fold_adaptor);
157 
158     template<class... Ts>
159     constexpr BOOST_HOF_SFINAE_RESULT(detail::v_reverse_fold, id_<const detail::callable_base<F>&>, id_<Ts>...)
160     operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS
161     (
162         detail::v_reverse_fold()(
163             BOOST_HOF_MANGLE_CAST(const detail::callable_base<F>&)(BOOST_HOF_CONST_THIS->base_function(xs...)),
164             BOOST_HOF_FORWARD(Ts)(xs)...
165         )
166     )
167 };
168 
169 BOOST_HOF_DECLARE_STATIC_VAR(reverse_fold, detail::make<reverse_fold_adaptor>);
170 
171 }} // namespace boost::hof
172 
173 #endif
174