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