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