| 1 | #include <algorithm>
|
|---|
| 2 | #include <boost/mpl/if.hpp>
|
|---|
| 3 | #include <boost/fusion/container/vector.hpp>
|
|---|
| 4 | #include <boost/proto/proto.hpp>
|
|---|
| 5 |
|
|---|
| 6 | namespace boost
|
|---|
| 7 | {
|
|---|
| 8 | namespace phoenix
|
|---|
| 9 | {
|
|---|
| 10 | using namespace proto;
|
|---|
| 11 |
|
|---|
| 12 | //////////////////////////////
|
|---|
| 13 | // phoenix expression wrapper
|
|---|
| 14 | template<class Expr>
|
|---|
| 15 | struct actor;
|
|---|
| 16 |
|
|---|
| 17 | //////////////////////////////
|
|---|
| 18 | struct phoenix_domain
|
|---|
| 19 | : domain<pod_generator<actor> >
|
|---|
| 20 | {};
|
|---|
| 21 |
|
|---|
| 22 | //////////////////////////////
|
|---|
| 23 | // phoenix grammar and expression evaluator
|
|---|
| 24 | struct eval
|
|---|
| 25 | : switch_<struct eval_cases>
|
|---|
| 26 | {};
|
|---|
| 27 |
|
|---|
| 28 | //////////////////////////////
|
|---|
| 29 | struct eval_cases
|
|---|
| 30 | {
|
|---|
| 31 | template<class Tag>
|
|---|
| 32 | struct case_
|
|---|
| 33 | : _default<eval>
|
|---|
| 34 | {};
|
|---|
| 35 | };
|
|---|
| 36 |
|
|---|
| 37 | //////////////////////////////
|
|---|
| 38 | template<class Sig>
|
|---|
| 39 | struct actor_result;
|
|---|
| 40 |
|
|---|
| 41 | #define BOOST_PROTO_LOCAL_MACRO(N, class_A, A, A_const_ref_a, a)\
|
|---|
| 42 | template<class Actor, class_A(N)> \
|
|---|
| 43 | struct actor_result<Actor(A(N))> \
|
|---|
| 44 | : boost::result_of<eval(Actor&, fusion::vector<A(N)> &)> \
|
|---|
| 45 | {};
|
|---|
| 46 |
|
|---|
| 47 | #define BOOST_PROTO_LOCAL_A BOOST_PROTO_A
|
|---|
| 48 | #include BOOST_PROTO_LOCAL_ITERATE()
|
|---|
| 49 |
|
|---|
| 50 | //////////////////////////////
|
|---|
| 51 | template<class Expr>
|
|---|
| 52 | struct actor
|
|---|
| 53 | {
|
|---|
| 54 | #define BOOST_PHOENIX_ACTOR(Base, Derived, Domain) \
|
|---|
| 55 | BOOST_PROTO_BASIC_EXTENDS(Base, Derived, Domain) \
|
|---|
| 56 | BOOST_PROTO_EXTENDS_ASSIGN() \
|
|---|
| 57 | BOOST_PROTO_EXTENDS_SUBSCRIPT() \
|
|---|
| 58 | \
|
|---|
| 59 | template<class Sig> \
|
|---|
| 60 | struct result : actor_result<Sig> \
|
|---|
| 61 | {}; \
|
|---|
| 62 | \
|
|---|
| 63 | typedef Derived actor_type; \
|
|---|
| 64 | BOOST_PROTO_REPEAT(BOOST_PHOENIX_INVOKE) \
|
|---|
| 65 | /**/
|
|---|
| 66 |
|
|---|
| 67 | #define BOOST_PHOENIX_INVOKE(N, class_A, A_const_ref, A_const_ref_a, a) \
|
|---|
| 68 | template<class_A(N)> \
|
|---|
| 69 | typename boost::result_of<actor_type(A_const_ref(N))>::type \
|
|---|
| 70 | operator()(A_const_ref_a(N)) const \
|
|---|
| 71 | { \
|
|---|
| 72 | BOOST_PROTO_ASSERT_MATCHES(*this, eval); \
|
|---|
| 73 | fusion::vector<A_const_ref(N)> args(a(N)); \
|
|---|
| 74 | return eval()(*this, args); \
|
|---|
| 75 | } \
|
|---|
| 76 | /**/
|
|---|
| 77 |
|
|---|
| 78 | BOOST_PHOENIX_ACTOR(Expr, actor<Expr>, phoenix_domain)
|
|---|
| 79 | };
|
|---|
| 80 |
|
|---|
| 81 | //////////////////////////////
|
|---|
| 82 | // Begin implementation of _1, _2, _3 argument placeholders
|
|---|
| 83 | //
|
|---|
| 84 | struct arg_tag {};
|
|---|
| 85 |
|
|---|
| 86 | //////////////////////////////
|
|---|
| 87 | struct at : callable
|
|---|
| 88 | {
|
|---|
| 89 | template<class Sig>
|
|---|
| 90 | struct result;
|
|---|
| 91 |
|
|---|
| 92 | template<class This, class Cont, class N>
|
|---|
| 93 | struct result<This(Cont &, N &)>
|
|---|
| 94 | : fusion::result_of::at<Cont, N>
|
|---|
| 95 | {};
|
|---|
| 96 |
|
|---|
| 97 | template<class Cont, class N>
|
|---|
| 98 | typename fusion::result_of::at<Cont, N>::type
|
|---|
| 99 | operator ()(Cont &cont, N) const
|
|---|
| 100 | {
|
|---|
| 101 | return fusion::at<N>(cont);
|
|---|
| 102 | }
|
|---|
| 103 | };
|
|---|
| 104 |
|
|---|
| 105 | //////////////////////////////
|
|---|
| 106 | actor<nullary_expr<arg_tag, mpl::int_<0> >::type> const _1 = {{{}}};
|
|---|
| 107 | actor<nullary_expr<arg_tag, mpl::int_<1> >::type> const _2 = {{{}}};
|
|---|
| 108 | actor<nullary_expr<arg_tag, mpl::int_<2> >::type> const _3 = {{{}}};
|
|---|
| 109 |
|
|---|
| 110 | //////////////////////////////
|
|---|
| 111 | template<>
|
|---|
| 112 | struct eval_cases::case_<arg_tag>
|
|---|
| 113 | : when<nullary_expr<arg_tag, _>, at(_state, _value)>
|
|---|
| 114 | {};
|
|---|
| 115 |
|
|---|
| 116 | //////////////////////////////
|
|---|
| 117 | // Begin implementation of if_/else_ here
|
|---|
| 118 | //
|
|---|
| 119 | struct if_tag {};
|
|---|
| 120 | struct else_tag {};
|
|---|
| 121 | struct if_else_tag {};
|
|---|
| 122 |
|
|---|
| 123 | template<class Expr>
|
|---|
| 124 | struct if_else_actor;
|
|---|
| 125 |
|
|---|
| 126 | // if_(x)[y]
|
|---|
| 127 | struct if_stmt
|
|---|
| 128 | : subscript<function<terminal<if_tag>, eval>, eval>
|
|---|
| 129 | {};
|
|---|
| 130 |
|
|---|
| 131 | // if_(x)[y].else_[z]
|
|---|
| 132 | struct if_else_stmt
|
|---|
| 133 | : subscript<
|
|---|
| 134 | member<unary_expr<if_tag, if_stmt>, terminal<else_tag> >
|
|---|
| 135 | , eval
|
|---|
| 136 | >
|
|---|
| 137 | {};
|
|---|
| 138 |
|
|---|
| 139 | typedef functional::make_expr<if_tag> make_if;
|
|---|
| 140 | typedef functional::make_expr<if_else_tag> make_if_else;
|
|---|
| 141 | typedef pod_generator<if_else_actor> make_if_else_actor;
|
|---|
| 142 |
|
|---|
| 143 | //////////////////////////////
|
|---|
| 144 | struct if_else_generator
|
|---|
| 145 | : or_<
|
|---|
| 146 | // if_(this)[that]
|
|---|
| 147 | when<
|
|---|
| 148 | if_stmt
|
|---|
| 149 | // wrap in if_else_actor and unary if_tag expr
|
|---|
| 150 | , make_if_else_actor(make_if(_byval(_)))
|
|---|
| 151 | >
|
|---|
| 152 | // if_(this)[that].else_[other]
|
|---|
| 153 | , when<
|
|---|
| 154 | if_else_stmt
|
|---|
| 155 | // wrap in if_else_actor and unary if_else_tag expr
|
|---|
| 156 | , make_if_else_actor(make_if_else(_byval(_)))
|
|---|
| 157 | >
|
|---|
| 158 | , otherwise<
|
|---|
| 159 | make_if_else_actor(_)
|
|---|
| 160 | >
|
|---|
| 161 | >
|
|---|
| 162 | {};
|
|---|
| 163 |
|
|---|
| 164 | //////////////////////////////
|
|---|
| 165 | struct if_else_domain
|
|---|
| 166 | : domain<if_else_generator>
|
|---|
| 167 | {};
|
|---|
| 168 |
|
|---|
| 169 | //////////////////////////////
|
|---|
| 170 | struct complete_if_else_stmt
|
|---|
| 171 | : or_<
|
|---|
| 172 | unary_expr<if_tag, if_stmt>
|
|---|
| 173 | , unary_expr<if_else_tag, if_else_stmt>
|
|---|
| 174 | >
|
|---|
| 175 | {};
|
|---|
| 176 |
|
|---|
| 177 | //////////////////////////////
|
|---|
| 178 | template<class Expr>
|
|---|
| 179 | struct if_else_actor
|
|---|
| 180 | {
|
|---|
| 181 | typedef typename
|
|---|
| 182 | mpl::if_<matches<Expr, complete_if_else_stmt>, phoenix_domain, if_else_domain>::type
|
|---|
| 183 | domain_;
|
|---|
| 184 |
|
|---|
| 185 | BOOST_PHOENIX_ACTOR(Expr, if_else_actor<Expr>, domain_)
|
|---|
| 186 |
|
|---|
| 187 | // Declare a member named else_ that is a
|
|---|
| 188 | // terminal<if_else_tag> in if_else_domain.
|
|---|
| 189 | BOOST_PROTO_EXTENDS_MEMBERS_WITH_DOMAIN(
|
|---|
| 190 | ((else_tag, else_))
|
|---|
| 191 | , if_else_domain
|
|---|
| 192 | )
|
|---|
| 193 | };
|
|---|
| 194 |
|
|---|
| 195 | // Function for evaluating lambdas like: if_(foo)[bar]
|
|---|
| 196 | struct if_eval : callable
|
|---|
| 197 | {
|
|---|
| 198 | typedef void result_type;
|
|---|
| 199 |
|
|---|
| 200 | template<class I, class T, class S>
|
|---|
| 201 | void operator()(I const & i, T const & t, S & s) const
|
|---|
| 202 | {
|
|---|
| 203 | if( eval()(i, s) )
|
|---|
| 204 | eval()(t, s);
|
|---|
| 205 | }
|
|---|
| 206 | };
|
|---|
| 207 |
|
|---|
| 208 | // Function for evaluating lambdas like: if_(foo)[bar].else_[baz]
|
|---|
| 209 | struct if_else_eval : callable
|
|---|
| 210 | {
|
|---|
| 211 | typedef void result_type;
|
|---|
| 212 |
|
|---|
| 213 | template<class I, class T, class E, class S>
|
|---|
| 214 | void operator()(I const & i, T const & t, E const & e, S & s) const
|
|---|
| 215 | {
|
|---|
| 216 | if( eval()(i, s) )
|
|---|
| 217 | eval()(t, s);
|
|---|
| 218 | else
|
|---|
| 219 | eval()(e, s);
|
|---|
| 220 | }
|
|---|
| 221 | };
|
|---|
| 222 |
|
|---|
| 223 | //////////////////////////////
|
|---|
| 224 | typedef functional::make_expr<tag::function, if_else_domain> make_fun;
|
|---|
| 225 |
|
|---|
| 226 | template<class E>
|
|---|
| 227 | typename boost::result_of<make_fun(if_tag, E const &)>::type const
|
|---|
| 228 | if_(E const & e)
|
|---|
| 229 | {
|
|---|
| 230 | return make_fun()(if_tag(), ref(e));
|
|---|
| 231 | }
|
|---|
| 232 |
|
|---|
| 233 | //////////////////////////////
|
|---|
| 234 | // This tells Proto how to evaluate if_(x)[y] statements with if_eval
|
|---|
| 235 | template<>
|
|---|
| 236 | struct eval_cases::case_<if_tag>
|
|---|
| 237 | : when<
|
|---|
| 238 | unary_expr<if_tag, if_stmt>
|
|---|
| 239 | , if_eval(_right(_left(_left)), _right(_left), _state)
|
|---|
| 240 | >
|
|---|
| 241 | {};
|
|---|
| 242 |
|
|---|
| 243 | //////////////////////////////
|
|---|
| 244 | // This tells Proto how to evaluate if(x)[y].else_[z] statements with if_else_eval
|
|---|
| 245 | template<>
|
|---|
| 246 | struct eval_cases::case_<if_else_tag>
|
|---|
| 247 | : when<
|
|---|
| 248 | unary_expr<if_else_tag, if_else_stmt>
|
|---|
| 249 | , if_else_eval(
|
|---|
| 250 | _right(_left(_left(_left(_left(_left)))))
|
|---|
| 251 | , _right(_left(_left(_left(_left))))
|
|---|
| 252 | , _right(_left)
|
|---|
| 253 | , _state
|
|---|
| 254 | )
|
|---|
| 255 | >
|
|---|
| 256 | {};
|
|---|
| 257 |
|
|---|
| 258 | } // namespace phoenix
|
|---|
| 259 | } // namespace boost
|
|---|
| 260 |
|
|---|
| 261 | #include <iostream>
|
|---|
| 262 | using namespace boost;
|
|---|
| 263 | using namespace phoenix;
|
|---|
| 264 |
|
|---|
| 265 | int main()
|
|---|
| 266 | {
|
|---|
| 267 | int j = (_1 + _2)(1, 2);
|
|---|
| 268 | std::cout << j << "\n";
|
|---|
| 269 |
|
|---|
| 270 | j = (_2 * 2)(1, 2);
|
|---|
| 271 | std::cout << j << "\n";
|
|---|
| 272 |
|
|---|
| 273 | phoenix::if_(_1)[std::cout << _2 << "\n"] + _1;
|
|---|
| 274 |
|
|---|
| 275 | phoenix::if_(_1)[std::cout << _2 << "\n"](1,2,3);
|
|---|
| 276 | phoenix::if_(_1)[std::cout << _2 << "\n"].else_[std::cout << _3 << "\n"](1,2,3);
|
|---|
| 277 | phoenix::if_(_1)[std::cout << _2 << "\n"].else_[std::cout << _3 << "\n"](0,2,3);
|
|---|
| 278 |
|
|---|
| 279 | int x[] = { 1, 2, 3, 4 };
|
|---|
| 280 | int y[] = { 2, 4, 6, 8 };
|
|---|
| 281 | int z[4];
|
|---|
| 282 |
|
|---|
| 283 | // Use a Phoenix lambda with std algorithms
|
|---|
| 284 | std::transform( x, x + 4, y, z, _1 * _2 );
|
|---|
| 285 | }
|
|---|