summaryrefslogtreecommitdiffstats
blob: 52a35e3e4092ff474b8e99fbe7a253682ab63f97 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
///////////////////////////////////////////////////////////////////////////////
/// \file fold.hpp
/// Contains definition of the fold<> and reverse_fold<> transforms.
//
//  Copyright 2008 Eric Niebler. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_PROTO_TRANSFORM_FOLD_HPP_EAN_11_04_2007
#define BOOST_PROTO_TRANSFORM_FOLD_HPP_EAN_11_04_2007

#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/iteration/iterate.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/fusion/include/fold.hpp>
#include <boost/fusion/include/reverse_fold.hpp>
#include <boost/proto/proto_fwd.hpp>
#include <boost/proto/traits.hpp>
#include <boost/proto/transform/impl.hpp>
#include <boost/proto/transform/when.hpp>

namespace boost { namespace proto
{
    namespace detail
    {
        template<typename Transform, typename Data>
        struct as_callable
        {
            as_callable(Data d)
              : d_(d)
            {}

            template<typename Sig>
            struct result;

            template<typename This, typename State, typename Expr>
            struct result<This(State, Expr)>
            {
                typedef
                    typename when<_, Transform>::template impl<Expr, State, Data>::result_type
                type;
            };

            template<typename State, typename Expr>
            typename when<_, Transform>::template impl<Expr &, State const &, Data>::result_type
            operator ()(State const &s, Expr &e) const
            {
                return typename when<_, Transform>::template impl<Expr &, State const &, Data>()(e, s, this->d_);
            }

        private:
            Data d_;
        };

        template<
            typename State0
          , typename Fun
          , typename Expr
          , typename State
          , typename Data
          , long Arity = arity_of<Expr>::value
        >
        struct fold_impl
        {};

        template<
            typename State0
          , typename Fun
          , typename Expr
          , typename State
          , typename Data
          , long Arity = arity_of<Expr>::value
        >
        struct reverse_fold_impl
        {};

        #include <boost/proto/transform/detail/fold_impl.hpp>

    } // namespace detail

    /// \brief A PrimitiveTransform that invokes the <tt>fusion::fold\<\></tt>
    /// algorithm to accumulate
    template<typename Sequence, typename State0, typename Fun>
    struct fold : transform<fold<Sequence, State0, Fun> >
    {
        template<typename Expr, typename State, typename Data>
        struct impl : transform_impl<Expr, State, Data>
        {
            /// \brief A Fusion sequence.
            typedef
                typename remove_reference<
                    typename when<_, Sequence>::template impl<Expr, State, Data>::result_type
                >::type
            sequence;

            /// \brief An initial state for the fold.
            typedef
                typename remove_reference<
                    typename when<_, State0>::template impl<Expr, State, Data>::result_type
                >::type
            state0;

            /// \brief <tt>fun(d)(e,s) == when\<_,Fun\>()(e,s,d)</tt>
            typedef
                detail::as_callable<Fun, Data>
            fun;

            typedef
                typename fusion::result_of::fold<
                    sequence
                  , state0
                  , fun
                >::type
            result_type;

            /// Let \c seq be <tt>when\<_, Sequence\>()(e, s, d)</tt>, let
            /// \c state0 be <tt>when\<_, State0\>()(e, s, d)</tt>, and
            /// let \c fun(d) be an object such that <tt>fun(d)(e, s)</tt>
            /// is equivalent to <tt>when\<_, Fun\>()(e, s, d)</tt>. Then, this
            /// function returns <tt>fusion::fold(seq, state0, fun(d))</tt>.
            ///
            /// \param e The current expression
            /// \param s The current state
            /// \param d An arbitrary data
            result_type operator ()(
                typename impl::expr_param   e
              , typename impl::state_param  s
              , typename impl::data_param   d
            ) const
            {
                typename when<_, Sequence>::template impl<Expr, State, Data> seq;
                detail::as_callable<Fun, Data> f(d);
                return fusion::fold(
                    seq(e, s, d)
                  , typename when<_, State0>::template impl<Expr, State, Data>()(e, s, d)
                  , f
                );
            }
        };
    };

    /// \brief A PrimitiveTransform that is the same as the
    /// <tt>fold\<\></tt> transform, except that it folds
    /// back-to-front instead of front-to-back.
    template<typename Sequence, typename State0, typename Fun>
    struct reverse_fold  : transform<reverse_fold<Sequence, State0, Fun> >
    {
        template<typename Expr, typename State, typename Data>
        struct impl : transform_impl<Expr, State, Data>
        {
            /// \brief A Fusion sequence.
            typedef
                typename remove_reference<
                    typename when<_, Sequence>::template impl<Expr, State, Data>::result_type
                >::type
            sequence;

            /// \brief An initial state for the fold.
            typedef
                typename remove_reference<
                    typename when<_, State0>::template impl<Expr, State, Data>::result_type
                >::type
            state0;

            /// \brief <tt>fun(d)(e,s) == when\<_,Fun\>()(e,s,d)</tt>
            typedef
                detail::as_callable<Fun, Data>
            fun;

            typedef
                typename fusion::result_of::reverse_fold<
                    sequence
                  , state0
                  , fun
                >::type
            result_type;

            /// Let \c seq be <tt>when\<_, Sequence\>()(e, s, d)</tt>, let
            /// \c state0 be <tt>when\<_, State0\>()(e, s, d)</tt>, and
            /// let \c fun(d) be an object such that <tt>fun(d)(e, s)</tt>
            /// is equivalent to <tt>when\<_, Fun\>()(e, s, d)</tt>. Then, this
            /// function returns <tt>fusion::fold(seq, state0, fun(d))</tt>.
            ///
            /// \param e The current expression
            /// \param s The current state
            /// \param d An arbitrary data
            result_type operator ()(
                typename impl::expr_param   e
              , typename impl::state_param  s
              , typename impl::data_param   d
            ) const
            {
                typename when<_, Sequence>::template impl<Expr, State, Data> seq;
                detail::as_callable<Fun, Data> f(d);
                return fusion::reverse_fold(
                    seq(e, s, d)
                  , typename when<_, State0>::template impl<Expr, State, Data>()(e, s, d)
                  , f
                );
            }
        };
    };

    // This specialization is only for improved compile-time performance
    // in the commom case when the Sequence transform is \c proto::_.
    //
    /// INTERNAL ONLY
    ///
    template<typename State0, typename Fun>
    struct fold<_, State0, Fun> : transform<fold<_, State0, Fun> >
    {
        template<typename Expr, typename State, typename Data>
        struct impl
          : detail::fold_impl<State0, Fun, Expr, State, Data>
        {};
    };

    // This specialization is only for improved compile-time performance
    // in the commom case when the Sequence transform is \c proto::_.
    //
    /// INTERNAL ONLY
    ///
    template<typename State0, typename Fun>
    struct reverse_fold<_, State0, Fun> : transform<reverse_fold<_, State0, Fun> >
    {
        template<typename Expr, typename State, typename Data>
        struct impl
          : detail::reverse_fold_impl<State0, Fun, Expr, State, Data>
        {};
    };

    /// INTERNAL ONLY
    ///
    template<typename Sequence, typename State, typename Fun>
    struct is_callable<fold<Sequence, State, Fun> >
      : mpl::true_
    {};

    /// INTERNAL ONLY
    ///
    template<typename Sequence, typename State, typename Fun>
    struct is_callable<reverse_fold<Sequence, State, Fun> >
      : mpl::true_
    {};

}}

#endif