• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
89namespace boost { namespace hof { namespace detail {
90
91struct 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>
102    constexpr State operator()(const F&, State&& state) const noexcept
103    {
104        return BOOST_HOF_FORWARD(State)(state);
105    }
106};
107
108}
109
110template<class F, class State=void>
111struct 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;
115    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>
124    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
144template<class F>
145struct reverse_fold_adaptor<F, void>
146: detail::callable_base<F>
147{
148    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
169BOOST_HOF_DECLARE_STATIC_VAR(reverse_fold, detail::make<reverse_fold_adaptor>);
170
171}} // namespace boost::hof
172
173#endif
174