1 /////////////////////////////////////////////////////////////////////////////// 2 /// \file fusion.hpp 3 /// Make any Proto expression a valid Fusion sequence 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_FUSION_HPP_EAN_11_04_2006 10 #define BOOST_PROTO_FUSION_HPP_EAN_11_04_2006 11 12 #include <boost/xpressive/proto/detail/prefix.hpp> 13 #include <boost/config.hpp> 14 #include <boost/version.hpp> 15 #include <boost/type_traits/remove_reference.hpp> 16 #include <boost/mpl/if.hpp> 17 #include <boost/mpl/long.hpp> 18 #if BOOST_VERSION >= 103500 19 #include <boost/fusion/include/is_view.hpp> 20 #include <boost/fusion/include/tag_of_fwd.hpp> 21 #include <boost/fusion/include/category_of.hpp> 22 #include <boost/fusion/include/iterator_base.hpp> 23 #include <boost/fusion/include/intrinsic.hpp> 24 #include <boost/fusion/include/pop_front.hpp> 25 #include <boost/fusion/include/reverse.hpp> 26 #include <boost/fusion/include/single_view.hpp> 27 #include <boost/fusion/include/transform_view.hpp> 28 #include <boost/fusion/support/ext_/is_segmented.hpp> 29 #include <boost/fusion/sequence/intrinsic/ext_/segments.hpp> 30 #include <boost/fusion/sequence/intrinsic/ext_/size_s.hpp> 31 #include <boost/fusion/view/ext_/segmented_iterator.hpp> 32 #else 33 #include <boost/spirit/fusion/sequence/is_sequence.hpp> 34 #include <boost/spirit/fusion/sequence/begin.hpp> 35 #include <boost/spirit/fusion/sequence/end.hpp> 36 #include <boost/spirit/fusion/sequence/at.hpp> 37 #include <boost/spirit/fusion/sequence/value_at.hpp> 38 #include <boost/spirit/fusion/sequence/single_view.hpp> 39 #include <boost/spirit/fusion/sequence/transform_view.hpp> 40 #include <boost/xpressive/proto/detail/reverse.hpp> 41 #include <boost/xpressive/proto/detail/pop_front.hpp> 42 #endif 43 #include <boost/xpressive/proto/proto_fwd.hpp> 44 #include <boost/xpressive/proto/traits.hpp> 45 #include <boost/xpressive/proto/eval.hpp> 46 #include <boost/xpressive/proto/detail/suffix.hpp> 47 48 #if BOOST_MSVC 49 #pragma warning(push) 50 #pragma warning(disable : 4510) // default constructor could not be generated 51 #pragma warning(disable : 4512) // assignment operator could not be generated 52 #pragma warning(disable : 4610) // can never be instantiated - user defined constructor required 53 #endif 54 55 namespace boost { namespace proto 56 { 57 58 /// INTERNAL ONLY 59 /// 60 #define UNREF(x) typename boost::remove_reference<x>::type 61 62 namespace detail 63 { 64 65 template<typename Expr, long Pos> 66 struct expr_iterator 67 : fusion::iterator_base<expr_iterator<Expr, Pos> > 68 { 69 typedef Expr expr_type; 70 BOOST_STATIC_CONSTANT(long, index = Pos); 71 BOOST_PROTO_DEFINE_FUSION_CATEGORY(fusion::random_access_traversal_tag) BOOST_PROTO_DEFINE_FUSION_TAGboost::proto::detail::expr_iterator72 BOOST_PROTO_DEFINE_FUSION_TAG(tag::proto_expr_iterator) 73 74 expr_iterator(Expr const &e) 75 : expr(e) 76 {} 77 78 Expr const &expr; 79 }; 80 81 template<typename Expr> 82 struct flat_view 83 { 84 typedef Expr expr_type; 85 typedef typename Expr::proto_tag proto_tag; 86 BOOST_PROTO_DEFINE_FUSION_CATEGORY(fusion::forward_traversal_tag) BOOST_PROTO_DEFINE_FUSION_TAGboost::proto::detail::flat_view87 BOOST_PROTO_DEFINE_FUSION_TAG(tag::proto_flat_view) 88 89 explicit flat_view(Expr &expr) 90 : expr_(expr) 91 {} 92 93 Expr &expr_; 94 }; 95 96 template<typename Tag> 97 struct as_element 98 { 99 template<typename Sig> 100 struct result; 101 102 template<typename This, typename Expr> 103 struct result<This(Expr)> 104 : mpl::if_< 105 is_same<Tag, UNREF(Expr)::proto_tag> 106 , flat_view<UNREF(Expr) const> 107 , fusion::single_view<UNREF(Expr) const &> 108 > 109 {}; 110 111 template<typename Expr> 112 typename result<as_element(Expr const &)>::type operator ()boost::proto::detail::as_element113 operator ()(Expr const &expr) const 114 { 115 return typename result<as_element(Expr const &)>::type(expr); 116 } 117 }; 118 119 } 120 121 namespace functional 122 { 123 /// \brief A PolymorphicFunctionObject type that returns a "flattened" 124 /// view of a Proto expression tree. 125 /// 126 /// A PolymorphicFunctionObject type that returns a "flattened" 127 /// view of a Proto expression tree. For a tree with a top-most node 128 /// tag of type \c T, the elements of the flattened sequence are 129 /// determined by recursing into each child node with the same 130 /// tag type and returning those nodes of different type. So for 131 /// instance, the Proto expression tree corresponding to the 132 /// expression <tt>a | b | c</tt> has a flattened view with elements 133 /// [a, b, c], even though the tree is grouped as 134 /// <tt>((a | b) | c)</tt>. 135 struct flatten 136 { 137 BOOST_PROTO_CALLABLE() 138 139 template<typename Sig> 140 struct result; 141 142 template<typename This, typename Expr> 143 struct result<This(Expr)> 144 { 145 typedef proto::detail::flat_view<UNREF(Expr) const> type; 146 }; 147 148 template<typename Expr> operator ()boost::proto::functional::flatten149 proto::detail::flat_view<Expr const> operator ()(Expr const &expr) const 150 { 151 return proto::detail::flat_view<Expr const>(expr); 152 } 153 }; 154 155 /// \brief A PolymorphicFunctionObject type that invokes the 156 /// \c fusion::pop_front() algorithm on its argument. 157 /// 158 /// A PolymorphicFunctionObject type that invokes the 159 /// \c fusion::pop_front() algorithm on its argument. This is 160 /// useful for defining a CallableTransform like \c pop_front(_) 161 /// which removes the first child from a Proto expression node. 162 /// Such a transform might be used as the first argument to the 163 /// \c proto::transform::fold\<\> transform; that is, fold all but 164 /// the first child. 165 struct pop_front 166 { 167 BOOST_PROTO_CALLABLE() 168 169 template<typename Sig> 170 struct result; 171 172 template<typename This, typename Expr> 173 struct result<This(Expr)> 174 { 175 typedef 176 typename fusion::BOOST_PROTO_FUSION_RESULT_OF::pop_front<UNREF(Expr) const>::type 177 type; 178 }; 179 180 template<typename Expr> 181 typename fusion::BOOST_PROTO_FUSION_RESULT_OF::pop_front<Expr const>::type operator ()boost::proto::functional::pop_front182 operator ()(Expr const &expr) const 183 { 184 return fusion::pop_front(expr); 185 } 186 }; 187 188 /// \brief A PolymorphicFunctionObject type that invokes the 189 /// \c fusion::reverse() algorithm on its argument. 190 /// 191 /// A PolymorphicFunctionObject type that invokes the 192 /// \c fusion::reverse() algorithm on its argument. This is 193 /// useful for defining a CallableTransform like \c reverse(_) 194 /// which reverses the order of the children of a Proto 195 /// expression node. 196 struct reverse 197 { 198 BOOST_PROTO_CALLABLE() 199 200 template<typename Sig> 201 struct result; 202 203 template<typename This, typename Expr> 204 struct result<This(Expr)> 205 { 206 typedef 207 typename fusion::BOOST_PROTO_FUSION_RESULT_OF::reverse<UNREF(Expr) const>::type 208 type; 209 }; 210 211 template<typename Expr> 212 typename fusion::BOOST_PROTO_FUSION_RESULT_OF::reverse<Expr const>::type operator ()boost::proto::functional::reverse213 operator ()(Expr const &expr) const 214 { 215 return fusion::reverse(expr); 216 } 217 }; 218 } 219 220 /// \brief A PolymorphicFunctionObject type that returns a "flattened" 221 /// view of a Proto expression tree. 222 /// 223 /// \sa boost::proto::functional::flatten 224 functional::flatten const flatten = {}; 225 226 /// INTERNAL ONLY 227 /// 228 template<> 229 struct is_callable<functional::flatten> 230 : mpl::true_ 231 {}; 232 233 /// INTERNAL ONLY 234 /// 235 template<> 236 struct is_callable<functional::pop_front> 237 : mpl::true_ 238 {}; 239 240 /// INTERNAL ONLY 241 /// 242 template<> 243 struct is_callable<functional::reverse> 244 : mpl::true_ 245 {}; 246 247 /// INTERNAL ONLY 248 /// 249 template<typename Context> 250 struct eval_fun 251 { eval_funboost::proto::eval_fun252 explicit eval_fun(Context &ctx) 253 : ctx_(ctx) 254 {} 255 256 template<typename Sig> 257 struct result; 258 259 template<typename This, typename Expr> 260 struct result<This(Expr)> 261 { 262 typedef 263 typename proto::result_of::eval<UNREF(Expr), Context>::type 264 type; 265 }; 266 267 template<typename Expr> 268 typename proto::result_of::eval<Expr, Context>::type operator ()boost::proto::eval_fun269 operator ()(Expr &expr) const 270 { 271 return proto::eval(expr, this->ctx_); 272 } 273 274 private: 275 Context &ctx_; 276 }; 277 }} 278 279 // Don't bother emitting all this into the Doxygen-generated 280 // reference section. It's enough to say that Proto expressions 281 // are valid Fusion sequence without showing all this gunk. 282 #ifndef BOOST_PROTO_DOXYGEN_INVOKED 283 284 namespace boost { namespace fusion 285 { 286 #if BOOST_VERSION < 103500 287 template<typename Tag, typename Args, long Arity> 288 struct is_sequence<proto::expr<Tag, Args, Arity> > 289 : mpl::true_ 290 {}; 291 292 template<typename Tag, typename Args, long Arity> 293 struct is_sequence<proto::expr<Tag, Args, Arity> const> 294 : mpl::true_ 295 {}; 296 #endif 297 298 namespace BOOST_PROTO_FUSION_EXTENSION 299 { 300 301 template<typename Tag> 302 struct is_view_impl; 303 304 template<> 305 struct is_view_impl<proto::tag::proto_flat_view> 306 { 307 template<typename Sequence> 308 struct apply 309 : mpl::true_ 310 {}; 311 }; 312 313 template<> 314 struct is_view_impl<proto::tag::proto_expr> 315 { 316 template<typename Sequence> 317 struct apply 318 : mpl::false_ 319 {}; 320 }; 321 322 template<typename Tag> 323 struct value_of_impl; 324 325 template<> 326 struct value_of_impl<proto::tag::proto_expr_iterator> 327 { 328 template< 329 typename Iterator 330 , typename Value = typename proto::result_of::arg_c< 331 typename Iterator::expr_type 332 , Iterator::index 333 >::wrapped_type 334 > 335 struct apply 336 { 337 typedef Value type; 338 }; 339 340 template<typename Iterator, typename Expr> 341 struct apply<Iterator, proto::ref_<Expr> > 342 { 343 typedef Expr &type; 344 }; 345 }; 346 347 #if BOOST_VERSION < 103500 348 template<typename Tag> 349 struct value_impl; 350 351 template<> 352 struct value_impl<proto::tag::proto_expr_iterator> 353 : value_of_impl<proto::tag::proto_expr_iterator> 354 {}; 355 #endif 356 357 template<typename Tag> 358 struct deref_impl; 359 360 template<> 361 struct deref_impl<proto::tag::proto_expr_iterator> 362 { 363 template<typename Iterator> 364 struct apply 365 { 366 typedef 367 typename proto::result_of::arg_c< 368 typename Iterator::expr_type const 369 , Iterator::index 370 >::type const & 371 type; 372 callboost::fusion::BOOST_PROTO_FUSION_EXTENSION::deref_impl::apply373 static type call(Iterator const &iter) 374 { 375 return proto::arg_c<Iterator::index>(iter.expr); 376 } 377 }; 378 }; 379 380 template<typename Tag> 381 struct advance_impl; 382 383 template<> 384 struct advance_impl<proto::tag::proto_expr_iterator> 385 { 386 template<typename Iterator, typename N> 387 struct apply 388 { 389 typedef 390 typename proto::detail::expr_iterator< 391 typename Iterator::expr_type 392 , Iterator::index + N::value 393 > 394 type; 395 callboost::fusion::BOOST_PROTO_FUSION_EXTENSION::advance_impl::apply396 static type call(Iterator const &iter) 397 { 398 return type(iter.expr); 399 } 400 }; 401 }; 402 403 template<typename Tag> 404 struct distance_impl; 405 406 template<> 407 struct distance_impl<proto::tag::proto_expr_iterator> 408 { 409 template<typename IteratorFrom, typename IteratorTo> 410 struct apply 411 : mpl::long_<IteratorTo::index - IteratorFrom::index> 412 {}; 413 }; 414 415 template<typename Tag> 416 struct next_impl; 417 418 template<> 419 struct next_impl<proto::tag::proto_expr_iterator> 420 { 421 template<typename Iterator> 422 struct apply 423 : advance_impl<proto::tag::proto_expr_iterator>::template apply<Iterator, mpl::long_<1> > 424 {}; 425 }; 426 427 template<typename Tag> 428 struct prior_impl; 429 430 template<> 431 struct prior_impl<proto::tag::proto_expr_iterator> 432 { 433 template<typename Iterator> 434 struct apply 435 : advance_impl<proto::tag::proto_expr_iterator>::template apply<Iterator, mpl::long_<-1> > 436 {}; 437 }; 438 439 #if BOOST_VERSION >= 103500 440 template<typename Tag> 441 struct category_of_impl; 442 443 template<> 444 struct category_of_impl<proto::tag::proto_expr> 445 { 446 template<typename Sequence> 447 struct apply 448 { 449 typedef random_access_traversal_tag type; 450 }; 451 }; 452 #endif 453 454 template<typename Tag> 455 struct size_impl; 456 457 template<> 458 struct size_impl<proto::tag::proto_expr> 459 { 460 template<typename Sequence> 461 struct apply 462 : mpl::long_<0 == Sequence::proto_arity::value ? 1 : Sequence::proto_arity::value> 463 {}; 464 }; 465 466 template<typename Tag> 467 struct begin_impl; 468 469 template<> 470 struct begin_impl<proto::tag::proto_expr> 471 { 472 template<typename Sequence> 473 struct apply 474 { 475 typedef proto::detail::expr_iterator<Sequence, 0> type; 476 callboost::fusion::BOOST_PROTO_FUSION_EXTENSION::begin_impl::apply477 static type call(Sequence const &seq) 478 { 479 return type(seq); 480 } 481 }; 482 }; 483 484 template<typename Tag> 485 struct end_impl; 486 487 template<> 488 struct end_impl<proto::tag::proto_expr> 489 { 490 template<typename Sequence> 491 struct apply 492 { 493 typedef 494 proto::detail::expr_iterator< 495 Sequence 496 , 0 == Sequence::proto_arity::value ? 1 : Sequence::proto_arity::value 497 > 498 type; 499 callboost::fusion::BOOST_PROTO_FUSION_EXTENSION::end_impl::apply500 static type call(Sequence const &seq) 501 { 502 return type(seq); 503 } 504 }; 505 }; 506 507 template<typename Tag> 508 struct value_at_impl; 509 510 template<> 511 struct value_at_impl<proto::tag::proto_expr> 512 { 513 template< 514 typename Sequence 515 , typename Index 516 , typename Value = typename proto::result_of::arg_c< 517 Sequence 518 , Index::value 519 >::wrapped_type 520 > 521 struct apply 522 { 523 typedef Value type; 524 }; 525 526 template<typename Sequence, typename Index, typename Expr> 527 struct apply<Sequence, Index, proto::ref_<Expr> > 528 { 529 typedef Expr &type; 530 }; 531 532 template<typename Sequence, typename Index, typename Expr> 533 struct apply<Sequence, Index, Expr &> 534 { 535 typedef Expr &type; 536 }; 537 }; 538 539 template<typename Tag> 540 struct at_impl; 541 542 template<> 543 struct at_impl<proto::tag::proto_expr> 544 { 545 template<typename Sequence, typename Index> 546 struct apply 547 { 548 typedef 549 typename proto::result_of::arg_c< 550 Sequence 551 , Index::value 552 >::reference 553 type; 554 callboost::fusion::BOOST_PROTO_FUSION_EXTENSION::at_impl::apply555 static type call(Sequence &seq) 556 { 557 return proto::arg_c<Index::value>(seq); 558 } 559 }; 560 561 template<typename Sequence, typename Index> 562 struct apply<Sequence const, Index> 563 { 564 typedef 565 typename proto::result_of::arg_c< 566 Sequence 567 , Index::value 568 >::const_reference 569 type; 570 callboost::fusion::BOOST_PROTO_FUSION_EXTENSION::at_impl::apply571 static type call(Sequence const &seq) 572 { 573 return proto::arg_c<Index::value>(seq); 574 } 575 }; 576 }; 577 578 #if BOOST_VERSION >= 103500 579 template<typename Tag> 580 struct is_segmented_impl; 581 582 template<> 583 struct is_segmented_impl<proto::tag::proto_flat_view> 584 { 585 template<typename Iterator> 586 struct apply 587 : mpl::true_ 588 {}; 589 }; 590 591 template<typename Tag> 592 struct segments_impl; 593 594 template<> 595 struct segments_impl<proto::tag::proto_flat_view> 596 { 597 template<typename Sequence> 598 struct apply 599 { 600 typedef typename Sequence::proto_tag proto_tag; 601 602 typedef fusion::transform_view< 603 typename Sequence::expr_type 604 , proto::detail::as_element<proto_tag> 605 > type; 606 callboost::fusion::BOOST_PROTO_FUSION_EXTENSION::segments_impl::apply607 static type call(Sequence &sequence) 608 { 609 return type(sequence.expr_, proto::detail::as_element<proto_tag>()); 610 } 611 }; 612 }; 613 614 template<> 615 struct category_of_impl<proto::tag::proto_flat_view> 616 { 617 template<typename Sequence> 618 struct apply 619 { 620 typedef forward_traversal_tag type; 621 }; 622 }; 623 624 template<> 625 struct begin_impl<proto::tag::proto_flat_view> 626 { 627 template<typename Sequence> 628 struct apply 629 : fusion::segmented_begin<Sequence> 630 {}; 631 }; 632 633 template<> 634 struct end_impl<proto::tag::proto_flat_view> 635 { 636 template<typename Sequence> 637 struct apply 638 : fusion::segmented_end<Sequence> 639 {}; 640 }; 641 642 template<> 643 struct size_impl<proto::tag::proto_flat_view> 644 { 645 template<typename Sequence> 646 struct apply 647 : fusion::segmented_size<Sequence> 648 {}; 649 }; 650 #endif 651 652 } 653 654 }} 655 656 #endif // BOOST_PROTO_DOXYGEN_INVOKED 657 658 #undef UNREF 659 660 #if BOOST_MSVC 661 #pragma warning(pop) 662 #endif 663 664 #endif 665