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/config.hpp> 13 #include <boost/mpl/if.hpp> 14 #include <boost/mpl/bool.hpp> 15 #include <boost/mpl/long.hpp> 16 #include <boost/mpl/sequence_tag_fwd.hpp> 17 #include <boost/utility/enable_if.hpp> 18 #include <boost/fusion/include/is_view.hpp> 19 #include <boost/fusion/include/tag_of_fwd.hpp> 20 #include <boost/fusion/include/category_of.hpp> 21 #include <boost/fusion/include/iterator_base.hpp> 22 #include <boost/fusion/include/intrinsic.hpp> 23 #include <boost/fusion/include/single_view.hpp> 24 #include <boost/fusion/include/transform_view.hpp> 25 #include <boost/fusion/support/ext_/is_segmented.hpp> 26 #include <boost/fusion/sequence/intrinsic/ext_/segments.hpp> 27 #include <boost/fusion/sequence/intrinsic/ext_/size_s.hpp> 28 #include <boost/fusion/sequence/comparison/enable_comparison.hpp> 29 #include <boost/fusion/view/ext_/segmented_iterator.hpp> 30 #include <boost/proto/proto_fwd.hpp> 31 #include <boost/proto/traits.hpp> 32 #include <boost/proto/eval.hpp> 33 34 #ifdef BOOST_MSVC 35 #pragma warning(push) 36 #pragma warning(disable : 4510) // default constructor could not be generated 37 #pragma warning(disable : 4512) // assignment operator could not be generated 38 #pragma warning(disable : 4610) // can never be instantiated - user defined constructor required 39 #endif 40 41 namespace boost { namespace proto 42 { 43 namespace detail 44 { 45 template<typename Expr, long Pos> 46 struct expr_iterator 47 : fusion::iterator_base<expr_iterator<Expr, Pos> > 48 { 49 typedef Expr expr_type; 50 typedef typename Expr::proto_tag proto_tag; 51 static const long index = Pos; 52 typedef fusion::random_access_traversal_tag category; 53 typedef tag::proto_expr_iterator fusion_tag; 54 expr_iteratorboost::proto::detail::expr_iterator55 expr_iterator(Expr &e) 56 : expr(e) 57 {} 58 59 Expr &expr; 60 }; 61 62 template<typename Expr> 63 struct flat_view 64 { 65 typedef Expr expr_type; 66 typedef typename Expr::proto_tag proto_tag; 67 typedef fusion::forward_traversal_tag category; 68 typedef tag::proto_flat_view fusion_tag; 69 flat_viewboost::proto::detail::flat_view70 explicit flat_view(Expr &e) 71 : expr_(e) 72 {} 73 74 Expr &expr_; 75 }; 76 77 template<typename Tag> 78 struct as_element 79 { 80 template<typename Sig> 81 struct result; 82 83 template<typename This, typename Expr> 84 struct result<This(Expr)> 85 : result<This(Expr const &)> 86 {}; 87 88 template<typename This, typename Expr> 89 struct result<This(Expr &)> 90 : mpl::if_c< 91 is_same<Tag, typename Expr::proto_tag>::value 92 , flat_view<Expr> 93 , fusion::single_view<Expr &> 94 > 95 {}; 96 97 template<typename Expr> 98 typename result<as_element(Expr &)>::type const operator ()boost::proto::detail::as_element99 operator ()(Expr &e) const 100 { 101 return typename result<as_element(Expr &)>::type(e); 102 } 103 104 template<typename Expr> 105 typename result<as_element(Expr const &)>::type const operator ()boost::proto::detail::as_element106 operator ()(Expr const &e) const 107 { 108 return typename result<as_element(Expr const &)>::type(e); 109 } 110 }; 111 } 112 113 namespace result_of 114 { 115 template<typename Expr> 116 struct flatten 117 : flatten<Expr const &> 118 {}; 119 120 template<typename Expr> 121 struct flatten<Expr &> 122 { 123 typedef detail::flat_view<Expr> type; 124 }; 125 } 126 127 namespace functional 128 { 129 /// \brief A PolymorphicFunctionObject type that returns a "flattened" 130 /// view of a Proto expression tree. 131 /// 132 /// A PolymorphicFunctionObject type that returns a "flattened" 133 /// view of a Proto expression tree. For a tree with a top-most node 134 /// tag of type \c T, the elements of the flattened sequence are 135 /// determined by recursing into each child node with the same 136 /// tag type and returning those nodes of different type. So for 137 /// instance, the Proto expression tree corresponding to the 138 /// expression <tt>a | b | c</tt> has a flattened view with elements 139 /// [a, b, c], even though the tree is grouped as 140 /// <tt>((a | b) | c)</tt>. 141 struct flatten 142 { 143 BOOST_PROTO_CALLABLE() 144 145 template<typename Sig> 146 struct result; 147 148 template<typename This, typename Expr> 149 struct result<This(Expr)> 150 : result<This(Expr const &)> 151 {}; 152 153 template<typename This, typename Expr> 154 struct result<This(Expr &)> 155 { 156 typedef proto::detail::flat_view<Expr> type; 157 }; 158 159 template<typename Expr> 160 proto::detail::flat_view<Expr> const operator ()boost::proto::functional::flatten161 operator ()(Expr &e) const 162 { 163 return proto::detail::flat_view<Expr>(e); 164 } 165 166 template<typename Expr> 167 proto::detail::flat_view<Expr const> const operator ()boost::proto::functional::flatten168 operator ()(Expr const &e) const 169 { 170 return proto::detail::flat_view<Expr const>(e); 171 } 172 }; 173 } 174 175 /// \brief A function that returns a "flattened" 176 /// view of a Proto expression tree. 177 /// 178 /// For a tree with a top-most node 179 /// tag of type \c T, the elements of the flattened sequence are 180 /// determined by recursing into each child node with the same 181 /// tag type and returning those nodes of different type. So for 182 /// instance, the Proto expression tree corresponding to the 183 /// expression <tt>a | b | c</tt> has a flattened view with elements 184 /// [a, b, c], even though the tree is grouped as 185 /// <tt>((a | b) | c)</tt>. 186 template<typename Expr> 187 proto::detail::flat_view<Expr> const flatten(Expr & e)188 flatten(Expr &e) 189 { 190 return proto::detail::flat_view<Expr>(e); 191 } 192 193 /// \overload 194 /// 195 template<typename Expr> 196 proto::detail::flat_view<Expr const> const flatten(Expr const & e)197 flatten(Expr const &e) 198 { 199 return proto::detail::flat_view<Expr const>(e); 200 } 201 202 /// INTERNAL ONLY 203 /// 204 template<typename Context> 205 struct eval_fun 206 : proto::callable 207 { eval_funboost::proto::eval_fun208 explicit eval_fun(Context &ctx) 209 : ctx_(ctx) 210 {} 211 212 template<typename Sig> 213 struct result; 214 215 template<typename This, typename Expr> 216 struct result<This(Expr)> 217 : result<This(Expr const &)> 218 {}; 219 220 template<typename This, typename Expr> 221 struct result<This(Expr &)> 222 : proto::result_of::eval<Expr, Context> 223 {}; 224 225 template<typename Expr> 226 typename proto::result_of::eval<Expr, Context>::type operator ()boost::proto::eval_fun227 operator ()(Expr &e) const 228 { 229 return proto::eval(e, this->ctx_); 230 } 231 232 template<typename Expr> 233 typename proto::result_of::eval<Expr const, Context>::type operator ()boost::proto::eval_fun234 operator ()(Expr const &e) const 235 { 236 return proto::eval(e, this->ctx_); 237 } 238 239 private: 240 Context &ctx_; 241 }; 242 243 /// INTERNAL ONLY 244 /// 245 template<typename Context> 246 struct is_callable<eval_fun<Context> > 247 : mpl::true_ 248 {}; 249 }} 250 251 namespace boost { namespace fusion 252 { 253 namespace extension 254 { 255 template<typename Tag> 256 struct is_sequence_impl; 257 258 template<> 259 struct is_sequence_impl<proto::tag::proto_flat_view> 260 { 261 template<typename Sequence> 262 struct apply 263 : mpl::true_ 264 {}; 265 }; 266 267 template<> 268 struct is_sequence_impl<proto::tag::proto_expr> 269 { 270 template<typename Sequence> 271 struct apply 272 : mpl::true_ 273 {}; 274 }; 275 276 template<typename Tag> 277 struct is_view_impl; 278 279 template<> 280 struct is_view_impl<proto::tag::proto_flat_view> 281 { 282 template<typename Sequence> 283 struct apply 284 : mpl::true_ 285 {}; 286 }; 287 288 template<> 289 struct is_view_impl<proto::tag::proto_expr> 290 { 291 template<typename Sequence> 292 struct apply 293 : mpl::false_ 294 {}; 295 }; 296 297 template<typename Tag> 298 struct value_of_impl; 299 300 template<> 301 struct value_of_impl<proto::tag::proto_expr_iterator> 302 { 303 template< 304 typename Iterator 305 , long Arity = proto::arity_of<typename Iterator::expr_type>::value 306 > 307 struct apply 308 { 309 typedef 310 typename proto::result_of::child_c< 311 typename Iterator::expr_type 312 , Iterator::index 313 >::value_type 314 type; 315 }; 316 317 template<typename Iterator> 318 struct apply<Iterator, 0> 319 { 320 typedef 321 typename proto::result_of::value< 322 typename Iterator::expr_type 323 >::value_type 324 type; 325 }; 326 }; 327 328 template<typename Tag> 329 struct deref_impl; 330 331 template<> 332 struct deref_impl<proto::tag::proto_expr_iterator> 333 { 334 template< 335 typename Iterator 336 , long Arity = proto::arity_of<typename Iterator::expr_type>::value 337 > 338 struct apply 339 { 340 typedef 341 typename proto::result_of::child_c< 342 typename Iterator::expr_type & 343 , Iterator::index 344 >::type 345 type; 346 callboost::fusion::extension::deref_impl::apply347 static type call(Iterator const &iter) 348 { 349 return proto::child_c<Iterator::index>(iter.expr); 350 } 351 }; 352 353 template<typename Iterator> 354 struct apply<Iterator, 0> 355 { 356 typedef 357 typename proto::result_of::value< 358 typename Iterator::expr_type & 359 >::type 360 type; 361 callboost::fusion::extension::deref_impl::apply362 static type call(Iterator const &iter) 363 { 364 return proto::value(iter.expr); 365 } 366 }; 367 }; 368 369 template<typename Tag> 370 struct advance_impl; 371 372 template<> 373 struct advance_impl<proto::tag::proto_expr_iterator> 374 { 375 template<typename Iterator, typename N> 376 struct apply 377 { 378 typedef 379 typename proto::detail::expr_iterator< 380 typename Iterator::expr_type 381 , Iterator::index + N::value 382 > 383 type; 384 callboost::fusion::extension::advance_impl::apply385 static type call(Iterator const &iter) 386 { 387 return type(iter.expr); 388 } 389 }; 390 }; 391 392 template<typename Tag> 393 struct distance_impl; 394 395 template<> 396 struct distance_impl<proto::tag::proto_expr_iterator> 397 { 398 template<typename IteratorFrom, typename IteratorTo> 399 struct apply 400 : mpl::long_<IteratorTo::index - IteratorFrom::index> 401 {}; 402 }; 403 404 template<typename Tag> 405 struct next_impl; 406 407 template<> 408 struct next_impl<proto::tag::proto_expr_iterator> 409 { 410 template<typename Iterator> 411 struct apply 412 : advance_impl<proto::tag::proto_expr_iterator>::template apply<Iterator, mpl::long_<1> > 413 {}; 414 }; 415 416 template<typename Tag> 417 struct prior_impl; 418 419 template<> 420 struct prior_impl<proto::tag::proto_expr_iterator> 421 { 422 template<typename Iterator> 423 struct apply 424 : advance_impl<proto::tag::proto_expr_iterator>::template apply<Iterator, mpl::long_<-1> > 425 {}; 426 }; 427 428 template<typename Tag> 429 struct category_of_impl; 430 431 template<> 432 struct category_of_impl<proto::tag::proto_expr> 433 { 434 template<typename Sequence> 435 struct apply 436 { 437 typedef random_access_traversal_tag type; 438 }; 439 }; 440 441 template<typename Tag> 442 struct size_impl; 443 444 template<> 445 struct size_impl<proto::tag::proto_expr> 446 { 447 template<typename Sequence> 448 struct apply 449 : mpl::long_<0 == Sequence::proto_arity_c ? 1 : Sequence::proto_arity_c> 450 {}; 451 }; 452 453 template<typename Tag> 454 struct begin_impl; 455 456 template<> 457 struct begin_impl<proto::tag::proto_expr> 458 { 459 template<typename Sequence> 460 struct apply 461 { 462 typedef proto::detail::expr_iterator<Sequence, 0> type; 463 callboost::fusion::extension::begin_impl::apply464 static type call(Sequence &seq) 465 { 466 return type(seq); 467 } 468 }; 469 }; 470 471 template<typename Tag> 472 struct end_impl; 473 474 template<> 475 struct end_impl<proto::tag::proto_expr> 476 { 477 template<typename Sequence> 478 struct apply 479 { 480 typedef 481 proto::detail::expr_iterator< 482 Sequence 483 , 0 == Sequence::proto_arity_c ? 1 : Sequence::proto_arity_c 484 > 485 type; 486 callboost::fusion::extension::end_impl::apply487 static type call(Sequence &seq) 488 { 489 return type(seq); 490 } 491 }; 492 }; 493 494 template<typename Tag> 495 struct value_at_impl; 496 497 template<> 498 struct value_at_impl<proto::tag::proto_expr> 499 { 500 template< 501 typename Sequence 502 , typename Index 503 , long Arity = proto::arity_of<Sequence>::value 504 > 505 struct apply 506 { 507 typedef 508 typename proto::result_of::child_c< 509 Sequence 510 , Index::value 511 >::value_type 512 type; 513 }; 514 515 template<typename Sequence, typename Index> 516 struct apply<Sequence, Index, 0> 517 { 518 typedef 519 typename proto::result_of::value< 520 Sequence 521 >::value_type 522 type; 523 }; 524 }; 525 526 template<typename Tag> 527 struct at_impl; 528 529 template<> 530 struct at_impl<proto::tag::proto_expr> 531 { 532 template< 533 typename Sequence 534 , typename Index 535 , long Arity = proto::arity_of<Sequence>::value 536 > 537 struct apply 538 { 539 typedef 540 typename proto::result_of::child_c< 541 Sequence & 542 , Index::value 543 >::type 544 type; 545 callboost::fusion::extension::at_impl::apply546 static type call(Sequence &seq) 547 { 548 return proto::child_c<Index::value>(seq); 549 } 550 }; 551 552 template<typename Sequence, typename Index> 553 struct apply<Sequence, Index, 0> 554 { 555 typedef 556 typename proto::result_of::value< 557 Sequence & 558 >::type 559 type; 560 callboost::fusion::extension::at_impl::apply561 static type call(Sequence &seq) 562 { 563 return proto::value(seq); 564 } 565 }; 566 }; 567 568 template<typename Tag> 569 struct is_segmented_impl; 570 571 template<> 572 struct is_segmented_impl<proto::tag::proto_flat_view> 573 { 574 template<typename Iterator> 575 struct apply 576 : mpl::true_ 577 {}; 578 }; 579 580 template<typename Tag> 581 struct segments_impl; 582 583 template<> 584 struct segments_impl<proto::tag::proto_flat_view> 585 { 586 template<typename Sequence> 587 struct apply 588 { 589 typedef typename Sequence::proto_tag proto_tag; 590 591 typedef fusion::transform_view< 592 typename Sequence::expr_type 593 , proto::detail::as_element<proto_tag> 594 > type; 595 callboost::fusion::extension::segments_impl::apply596 static type call(Sequence &sequence) 597 { 598 return type(sequence.expr_, proto::detail::as_element<proto_tag>()); 599 } 600 }; 601 }; 602 603 template<> 604 struct category_of_impl<proto::tag::proto_flat_view> 605 { 606 template<typename Sequence> 607 struct apply 608 { 609 typedef forward_traversal_tag type; 610 }; 611 }; 612 613 template<> 614 struct begin_impl<proto::tag::proto_flat_view> 615 { 616 template<typename Sequence> 617 struct apply 618 : fusion::segmented_begin<Sequence> 619 {}; 620 }; 621 622 template<> 623 struct end_impl<proto::tag::proto_flat_view> 624 { 625 template<typename Sequence> 626 struct apply 627 : fusion::segmented_end<Sequence> 628 {}; 629 }; 630 631 template<> 632 struct size_impl<proto::tag::proto_flat_view> 633 { 634 template<typename Sequence> 635 struct apply 636 : fusion::segmented_size<Sequence> 637 {}; 638 }; 639 640 } 641 642 namespace traits 643 { 644 template<typename Seq1, typename Seq2> 645 struct enable_equality< 646 Seq1 647 , Seq2 648 , typename enable_if_c< 649 mpl::or_< 650 proto::is_expr<Seq1> 651 , proto::is_expr<Seq2> 652 >::value 653 >::type 654 > 655 : mpl::false_ 656 {}; 657 658 template<typename Seq1, typename Seq2> 659 struct enable_comparison< 660 Seq1 661 , Seq2 662 , typename enable_if_c< 663 mpl::or_< 664 proto::is_expr<Seq1> 665 , proto::is_expr<Seq2> 666 >::value 667 >::type 668 > 669 : mpl::false_ 670 {}; 671 } 672 673 }} 674 675 namespace boost { namespace mpl 676 { 677 template<typename Tag, typename Args, long Arity> 678 struct sequence_tag< proto::expr<Tag, Args, Arity> > 679 { 680 typedef fusion::fusion_sequence_tag type; 681 }; 682 683 template<typename Tag, typename Args, long Arity> 684 struct sequence_tag< proto::basic_expr<Tag, Args, Arity> > 685 { 686 typedef fusion::fusion_sequence_tag type; 687 }; 688 }} 689 690 #ifdef BOOST_MSVC 691 #pragma warning(pop) 692 #endif 693 694 #endif 695