1 ///////////////////////////////////////////////////////////////////////////////
2 /// \file fold.hpp
3 /// Contains definition of the fold<> and reverse_fold<> transforms.
4 //
5 //  Copyright 2008 Eric Niebler. Distributed under the Boost
6 //  Software License, Version 1.0. (See accompanying file
7 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 
9 #ifndef BOOST_PROTO_TRANSFORM_FOLD_HPP_EAN_11_04_2007
10 #define BOOST_PROTO_TRANSFORM_FOLD_HPP_EAN_11_04_2007
11 
12 #include <boost/preprocessor/cat.hpp>
13 #include <boost/preprocessor/iteration/iterate.hpp>
14 #include <boost/preprocessor/arithmetic/inc.hpp>
15 #include <boost/preprocessor/arithmetic/sub.hpp>
16 #include <boost/preprocessor/repetition/repeat.hpp>
17 #include <boost/fusion/include/fold.hpp>
18 #include <boost/fusion/include/reverse_fold.hpp>
19 #include <boost/proto/proto_fwd.hpp>
20 #include <boost/proto/traits.hpp>
21 #include <boost/proto/transform/impl.hpp>
22 #include <boost/proto/transform/when.hpp>
23 
24 namespace boost { namespace proto
25 {
26     namespace detail
27     {
28         template<typename Transform, typename Data>
29         struct as_callable
30         {
as_callableboost::proto::detail::as_callable31             as_callable(Data d)
32               : d_(d)
33             {}
34 
35             template<typename Sig>
36             struct result;
37 
38             template<typename This, typename State, typename Expr>
39             struct result<This(State, Expr)>
40             {
41                 typedef
42                     typename when<_, Transform>::template impl<Expr, State, Data>::result_type
43                 type;
44             };
45 
46             template<typename State, typename Expr>
47             typename when<_, Transform>::template impl<Expr &, State const &, Data>::result_type
operator ()boost::proto::detail::as_callable48             operator ()(State const &s, Expr &e) const
49             {
50                 return typename when<_, Transform>::template impl<Expr &, State const &, Data>()(e, s, this->d_);
51             }
52 
53         private:
54             Data d_;
55         };
56 
57         template<
58             typename State0
59           , typename Fun
60           , typename Expr
61           , typename State
62           , typename Data
63           , long Arity = arity_of<Expr>::value
64         >
65         struct fold_impl
66         {};
67 
68         template<
69             typename State0
70           , typename Fun
71           , typename Expr
72           , typename State
73           , typename Data
74           , long Arity = arity_of<Expr>::value
75         >
76         struct reverse_fold_impl
77         {};
78 
79         #include <boost/proto/transform/detail/fold_impl.hpp>
80 
81     } // namespace detail
82 
83     /// \brief A PrimitiveTransform that invokes the <tt>fusion::fold\<\></tt>
84     /// algorithm to accumulate
85     template<typename Sequence, typename State0, typename Fun>
86     struct fold : transform<fold<Sequence, State0, Fun> >
87     {
88         template<typename Expr, typename State, typename Data>
89         struct impl : transform_impl<Expr, State, Data>
90         {
91             /// \brief A Fusion sequence.
92             typedef
93                 typename remove_reference<
94                     typename when<_, Sequence>::template impl<Expr, State, Data>::result_type
95                 >::type
96             sequence;
97 
98             /// \brief An initial state for the fold.
99             typedef
100                 typename remove_reference<
101                     typename when<_, State0>::template impl<Expr, State, Data>::result_type
102                 >::type
103             state0;
104 
105             /// \brief <tt>fun(d)(e,s) == when\<_,Fun\>()(e,s,d)</tt>
106             typedef
107                 detail::as_callable<Fun, Data>
108             fun;
109 
110             typedef
111                 typename fusion::result_of::fold<
112                     sequence
113                   , state0
114                   , fun
115                 >::type
116             result_type;
117 
118             /// Let \c seq be <tt>when\<_, Sequence\>()(e, s, d)</tt>, let
119             /// \c state0 be <tt>when\<_, State0\>()(e, s, d)</tt>, and
120             /// let \c fun(d) be an object such that <tt>fun(d)(e, s)</tt>
121             /// is equivalent to <tt>when\<_, Fun\>()(e, s, d)</tt>. Then, this
122             /// function returns <tt>fusion::fold(seq, state0, fun(d))</tt>.
123             ///
124             /// \param e The current expression
125             /// \param s The current state
126             /// \param d An arbitrary data
operator ()boost::proto::fold::impl127             result_type operator ()(
128                 typename impl::expr_param   e
129               , typename impl::state_param  s
130               , typename impl::data_param   d
131             ) const
132             {
133                 typename when<_, Sequence>::template impl<Expr, State, Data> seq;
134                 detail::as_callable<Fun, Data> f(d);
135                 return fusion::fold(
136                     seq(e, s, d)
137                   , typename when<_, State0>::template impl<Expr, State, Data>()(e, s, d)
138                   , f
139                 );
140             }
141         };
142     };
143 
144     /// \brief A PrimitiveTransform that is the same as the
145     /// <tt>fold\<\></tt> transform, except that it folds
146     /// back-to-front instead of front-to-back.
147     template<typename Sequence, typename State0, typename Fun>
148     struct reverse_fold  : transform<reverse_fold<Sequence, State0, Fun> >
149     {
150         template<typename Expr, typename State, typename Data>
151         struct impl : transform_impl<Expr, State, Data>
152         {
153             /// \brief A Fusion sequence.
154             typedef
155                 typename remove_reference<
156                     typename when<_, Sequence>::template impl<Expr, State, Data>::result_type
157                 >::type
158             sequence;
159 
160             /// \brief An initial state for the fold.
161             typedef
162                 typename remove_reference<
163                     typename when<_, State0>::template impl<Expr, State, Data>::result_type
164                 >::type
165             state0;
166 
167             /// \brief <tt>fun(d)(e,s) == when\<_,Fun\>()(e,s,d)</tt>
168             typedef
169                 detail::as_callable<Fun, Data>
170             fun;
171 
172             typedef
173                 typename fusion::result_of::reverse_fold<
174                     sequence
175                   , state0
176                   , fun
177                 >::type
178             result_type;
179 
180             /// Let \c seq be <tt>when\<_, Sequence\>()(e, s, d)</tt>, let
181             /// \c state0 be <tt>when\<_, State0\>()(e, s, d)</tt>, and
182             /// let \c fun(d) be an object such that <tt>fun(d)(e, s)</tt>
183             /// is equivalent to <tt>when\<_, Fun\>()(e, s, d)</tt>. Then, this
184             /// function returns <tt>fusion::fold(seq, state0, fun(d))</tt>.
185             ///
186             /// \param e The current expression
187             /// \param s The current state
188             /// \param d An arbitrary data
operator ()boost::proto::reverse_fold::impl189             result_type operator ()(
190                 typename impl::expr_param   e
191               , typename impl::state_param  s
192               , typename impl::data_param   d
193             ) const
194             {
195                 typename when<_, Sequence>::template impl<Expr, State, Data> seq;
196                 detail::as_callable<Fun, Data> f(d);
197                 return fusion::reverse_fold(
198                     seq(e, s, d)
199                   , typename when<_, State0>::template impl<Expr, State, Data>()(e, s, d)
200                   , f
201                 );
202             }
203         };
204     };
205 
206     // This specialization is only for improved compile-time performance
207     // in the commom case when the Sequence transform is \c proto::_.
208     //
209     /// INTERNAL ONLY
210     ///
211     template<typename State0, typename Fun>
212     struct fold<_, State0, Fun> : transform<fold<_, State0, Fun> >
213     {
214         template<typename Expr, typename State, typename Data>
215         struct impl
216           : detail::fold_impl<State0, Fun, Expr, State, Data>
217         {};
218     };
219 
220     // This specialization is only for improved compile-time performance
221     // in the commom case when the Sequence transform is \c proto::_.
222     //
223     /// INTERNAL ONLY
224     ///
225     template<typename State0, typename Fun>
226     struct reverse_fold<_, State0, Fun> : transform<reverse_fold<_, State0, Fun> >
227     {
228         template<typename Expr, typename State, typename Data>
229         struct impl
230           : detail::reverse_fold_impl<State0, Fun, Expr, State, Data>
231         {};
232     };
233 
234     /// INTERNAL ONLY
235     ///
236     template<typename Sequence, typename State, typename Fun>
237     struct is_callable<fold<Sequence, State, Fun> >
238       : mpl::true_
239     {};
240 
241     /// INTERNAL ONLY
242     ///
243     template<typename Sequence, typename State, typename Fun>
244     struct is_callable<reverse_fold<Sequence, State, Fun> >
245       : mpl::true_
246     {};
247 
248 }}
249 
250 #endif
251