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