1 /*=============================================================================
2     Copyright (c) 2001-2011 Hartmut Kaiser
3     Copyright (c) 2001-2011 Joel de Guzman
4 
5     Distributed under the Boost Software License, Version 1.0. (See accompanying
6     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 ==============================================================================*/
8 #if !defined(BOOST_SPIRIT_ANY_IF_MARCH_30_2007_1220PM)
9 #define BOOST_SPIRIT_ANY_IF_MARCH_30_2007_1220PM
10 
11 #if defined(_MSC_VER)
12 #pragma once
13 #endif
14 
15 #include <boost/fusion/include/equal_to.hpp>
16 #include <boost/fusion/include/next.hpp>
17 #include <boost/fusion/include/deref.hpp>
18 #include <boost/fusion/include/value_of.hpp>
19 #include <boost/fusion/include/begin.hpp>
20 #include <boost/fusion/include/end.hpp>
21 #include <boost/fusion/include/is_sequence.hpp>
22 #include <boost/fusion/include/any.hpp>
23 #include <boost/spirit/home/support/unused.hpp>
24 
25 #include <boost/mpl/bool.hpp>
26 #include <boost/mpl/apply.hpp>
27 #include <boost/mpl/if.hpp>
28 #include <boost/mpl/identity.hpp>
29 #include <boost/mpl/and.hpp>
30 #include <boost/mpl/not.hpp>
31 
32 namespace boost { namespace spirit
33 {
34     ///////////////////////////////////////////////////////////////////////////
35     //  This is a special version for a binary fusion::any. The predicate
36     //  is used to decide whether to advance the second iterator or not.
37     //  This is needed for sequences containing components with unused
38     //  attributes. The second iterator is advanced only if the attribute
39     //  of the corresponding component iterator is not unused.
40     ///////////////////////////////////////////////////////////////////////////
41     namespace detail
42     {
43         ///////////////////////////////////////////////////////////////////////
44         template <typename Iterator, typename Pred>
45         struct apply_predicate
46           : mpl::apply1<Pred, typename fusion::result_of::value_of<Iterator>::type>
47         {};
48 
49         ///////////////////////////////////////////////////////////////////////
50         //  if the predicate is true, attribute_next returns next(Iterator2),
51         //  otherwise Iterator2
52         namespace result_of
53         {
54             template <
55                 typename Iterator1, typename Iterator2, typename Last2
56               , typename Pred>
57             struct attribute_next
58             {
59                 typedef mpl::and_<
60                     apply_predicate<Iterator1, Pred>
61                   , mpl::not_<fusion::result_of::equal_to<Iterator2, Last2> >
62                 > pred;
63 
64                 typedef typename
65                     mpl::eval_if<
66                         pred
67                       , fusion::result_of::next<Iterator2>
68                       , mpl::identity<Iterator2>
69                     >::type
70                 type;
71 
72                 template <typename Iterator>
73                 static type
callboost::spirit::detail::result_of::attribute_next74                 call(Iterator const& i, mpl::true_)
75                 {
76                     return fusion::next(i);
77                 }
78 
79                 template <typename Iterator>
80                 static type
callboost::spirit::detail::result_of::attribute_next81                 call(Iterator const& i, mpl::false_)
82                 {
83                     return i;
84                 }
85 
86                 template <typename Iterator>
87                 static type
callboost::spirit::detail::result_of::attribute_next88                 call(Iterator const& i)
89                 {
90                     return call(i, pred());
91                 }
92             };
93         }
94 
95         template <
96             typename Pred, typename Iterator1, typename Last2
97           , typename Iterator2>
98         inline typename
99             result_of::attribute_next<Iterator1, Iterator2, Last2, Pred
100         >::type const
attribute_next(Iterator2 const & i)101         attribute_next(Iterator2 const& i)
102         {
103             return result_of::attribute_next<
104                 Iterator1, Iterator2, Last2, Pred>::call(i);
105         }
106 
107         ///////////////////////////////////////////////////////////////////////
108         //  if the predicate is true, attribute_value returns deref(Iterator2),
109         //  otherwise unused
110         namespace result_of
111         {
112             template <
113                 typename Iterator1, typename Iterator2, typename Last2
114               , typename Pred>
115             struct attribute_value
116             {
117                 typedef mpl::and_<
118                     apply_predicate<Iterator1, Pred>
119                   , mpl::not_<fusion::result_of::equal_to<Iterator2, Last2> >
120                 > pred;
121 
122                 typedef typename
123                     mpl::eval_if<
124                         pred
125                       , fusion::result_of::deref<Iterator2>
126                       , mpl::identity<unused_type const>
127                     >::type
128                 type;
129 
130                 template <typename Iterator>
131                 static type
callboost::spirit::detail::result_of::attribute_value132                 call(Iterator const& i, mpl::true_)
133                 {
134                     return fusion::deref(i);
135                 }
136 
137                 template <typename Iterator>
138                 static type
callboost::spirit::detail::result_of::attribute_value139                 call(Iterator const&, mpl::false_)
140                 {
141                     return unused;
142                 }
143 
144                 template <typename Iterator>
145                 static type
callboost::spirit::detail::result_of::attribute_value146                 call(Iterator const& i)
147                 {
148                     return call(i, pred());
149                 }
150             };
151         }
152 
153         template <
154             typename Pred, typename Iterator1, typename Last2
155           , typename Iterator2>
156         inline typename
157             result_of::attribute_value<Iterator1, Iterator2, Last2, Pred
158         >::type
attribute_value(Iterator2 const & i)159         attribute_value(Iterator2 const& i)
160         {
161             return result_of::attribute_value<
162                 Iterator1, Iterator2, Last2, Pred>::call(i);
163         }
164 
165         ///////////////////////////////////////////////////////////////////////
166         template <
167             typename Pred, typename First1, typename Last1, typename First2
168           , typename Last2, typename F>
169         inline bool
any_if(First1 const &,First2 const &,Last1 const &,Last2 const &,F const &,mpl::true_)170         any_if (First1 const&, First2 const&, Last1 const&, Last2 const&
171           , F const&, mpl::true_)
172         {
173             return false;
174         }
175 
176         template <
177             typename Pred, typename First1, typename Last1, typename First2
178           , typename Last2, typename F>
179         inline bool
any_if(First1 const & first1,First2 const & first2,Last1 const & last1,Last2 const & last2,F & f,mpl::false_)180         any_if (First1 const& first1, First2 const& first2, Last1 const& last1
181           , Last2 const& last2, F& f, mpl::false_)
182         {
183             typename result_of::attribute_value<First1, First2, Last2, Pred>::type
184                 attribute = spirit::detail::attribute_value<Pred, First1, Last2>(first2);
185 
186             return f(*first1, attribute) ||
187                 detail::any_if<Pred>(
188                     fusion::next(first1)
189                   , attribute_next<Pred, First1, Last2>(first2)
190                   , last1, last2
191                   , f
192                   , fusion::result_of::equal_to<
193                         typename fusion::result_of::next<First1>::type, Last1>());
194         }
195     }
196 
197     template <typename Pred, typename Sequence1, typename Sequence2, typename F>
198     inline bool
any_if(Sequence1 const & seq1,Sequence2 & seq2,F f,Pred)199     any_if(Sequence1 const& seq1, Sequence2& seq2, F f, Pred)
200     {
201         return detail::any_if<Pred>(
202                 fusion::begin(seq1), fusion::begin(seq2)
203               , fusion::end(seq1), fusion::end(seq2)
204               , f
205               , fusion::result_of::equal_to<
206                     typename fusion::result_of::begin<Sequence1>::type
207                   , typename fusion::result_of::end<Sequence1>::type>());
208     }
209 
210     template <typename Pred, typename Sequence, typename F>
211     inline bool
any_if(Sequence const & seq,unused_type const,F f,Pred)212     any_if(Sequence const& seq, unused_type const, F f, Pred)
213     {
214         return fusion::any(seq, f);
215     }
216 
217 }}
218 
219 #endif
220 
221