]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/include/boost/spirit/home/x3/operator/detail/alternative.hpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / spirit / include / boost / spirit / home / x3 / operator / detail / alternative.hpp
1 /*=============================================================================
2 Copyright (c) 2001-2014 Joel de Guzman
3
4 Distributed under the Boost Software License, Version 1.0. (See accompanying
5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 =============================================================================*/
7 #if !defined(SPIRIT_ALTERNATIVE_DETAIL_JAN_07_2013_1245PM)
8 #define SPIRIT_ALTERNATIVE_DETAIL_JAN_07_2013_1245PM
9
10 #include <boost/spirit/home/x3/support/traits/attribute_of.hpp>
11 #include <boost/spirit/home/x3/support/traits/is_variant.hpp>
12 #include <boost/spirit/home/x3/support/traits/tuple_traits.hpp>
13 #include <boost/spirit/home/x3/support/traits/move_to.hpp>
14 #include <boost/spirit/home/x3/support/traits/variant_has_substitute.hpp>
15 #include <boost/spirit/home/x3/support/traits/variant_find_substitute.hpp>
16 #include <boost/spirit/home/x3/core/detail/parse_into_container.hpp>
17 #include <boost/variant/variant.hpp>
18
19 #include <boost/mpl/copy_if.hpp>
20 #include <boost/mpl/not.hpp>
21 #include <boost/mpl/if.hpp>
22 #include <boost/mpl/insert_range.hpp>
23 #include <boost/mpl/eval_if.hpp>
24 #include <boost/mpl/vector.hpp>
25
26 #include <boost/fusion/include/front.hpp>
27
28 #include <boost/type_traits/is_same.hpp>
29
30 namespace boost { namespace spirit { namespace x3
31 {
32 template <typename Left, typename Right>
33 struct alternative;
34 }}}
35
36 namespace boost { namespace spirit { namespace x3 { namespace detail
37 {
38 struct pass_variant_unused
39 {
40 typedef unused_type type;
41
42 template <typename T>
43 static unused_type
44 call(T&)
45 {
46 return unused_type();
47 }
48 };
49
50 template <typename Attribute>
51 struct pass_variant_used
52 {
53 typedef Attribute& type;
54
55 static Attribute&
56 call(Attribute& v)
57 {
58 return v;
59 }
60 };
61
62 template <>
63 struct pass_variant_used<unused_type> : pass_variant_unused {};
64
65 template <typename Parser, typename Attribute, typename Context
66 , typename Enable = void>
67 struct pass_parser_attribute
68 {
69 typedef typename
70 traits::attribute_of<Parser, Context>::type
71 attribute_type;
72 typedef typename
73 traits::variant_find_substitute<Attribute, attribute_type>::type
74 substitute_type;
75
76 typedef typename
77 mpl::if_<
78 is_same<Attribute, substitute_type>
79 , Attribute&
80 , substitute_type
81 >::type
82 type;
83
84 template <typename Attribute_>
85 static Attribute_&
86 call(Attribute_& attr, mpl::true_)
87 {
88 return attr;
89 }
90
91 template <typename Attribute_>
92 static type
93 call(Attribute_&, mpl::false_)
94 {
95 return type();
96 }
97
98 template <typename Attribute_>
99 static type
100 call(Attribute_& attr)
101 {
102 return call(attr, is_same<Attribute_, typename remove_reference<type>::type>());
103 }
104 };
105
106 // Pass non-variant attributes as-is
107 template <typename Parser, typename Attribute, typename Context
108 , typename Enable = void>
109 struct pass_non_variant_attribute
110 {
111 typedef Attribute& type;
112
113 static Attribute&
114 call(Attribute& attr)
115 {
116 return attr;
117 }
118 };
119
120 // Unwrap single element sequences
121 template <typename Parser, typename Attribute, typename Context>
122 struct pass_non_variant_attribute<Parser, Attribute, Context,
123 typename enable_if<traits::is_size_one_sequence<Attribute>>::type>
124 {
125 typedef typename remove_reference<
126 typename fusion::result_of::front<Attribute>::type>::type
127 attr_type;
128
129 typedef pass_parser_attribute<Parser, attr_type, Context> pass;
130 typedef typename pass::type type;
131
132 template <typename Attribute_>
133 static type
134 call(Attribute_& attr)
135 {
136 return pass::call(fusion::front(attr));
137 }
138 };
139
140 template <typename Parser, typename Attribute, typename Context>
141 struct pass_parser_attribute<Parser, Attribute, Context,
142 typename enable_if_c<(!traits::is_variant<Attribute>::value)>::type>
143 : pass_non_variant_attribute<Parser, Attribute, Context>
144 {};
145
146 template <typename Parser, typename Context>
147 struct pass_parser_attribute<Parser, unused_type, Context>
148 : pass_variant_unused {};
149
150 template <typename Parser, typename Attribute, typename Context>
151 struct pass_variant_attribute :
152 mpl::if_c<traits::has_attribute<Parser, Context>::value
153 , pass_parser_attribute<Parser, Attribute, Context>
154 , pass_variant_unused>::type
155 {
156 typedef typename mpl::false_ is_alternative;
157 };
158
159 template <typename L, typename R, typename Attribute, typename Context>
160 struct pass_variant_attribute<alternative<L, R>, Attribute, Context> :
161 mpl::if_c<traits::has_attribute<alternative<L, R>, Context>::value
162 , pass_variant_used<Attribute>
163 , pass_variant_unused>::type
164 {
165 typedef typename mpl::true_ is_alternative;
166 };
167
168 template <typename L, typename R, typename C>
169 struct get_alternative_types
170 {
171 typedef
172 mpl::vector<
173 typename traits::attribute_of<L, C>::type
174 , typename traits::attribute_of<R, C>::type
175 >
176 type;
177 };
178
179 template <typename LL, typename LR, typename R, typename C>
180 struct get_alternative_types<alternative<LL, LR>, R, C>
181 : mpl::push_back< typename get_alternative_types<LL, LR, C>::type
182 , typename traits::attribute_of<R, C>::type> {};
183
184 template <typename L, typename RL, typename RR, typename C>
185 struct get_alternative_types<L, alternative<RL, RR>, C>
186 : mpl::push_front< typename get_alternative_types<RL, RR, C>::type
187 , typename traits::attribute_of<L, C>::type> {};
188
189 template <typename LL, typename LR, typename RL, typename RR, typename C>
190 struct get_alternative_types<alternative<LL, LR>, alternative<RL, RR>, C>
191 {
192 typedef typename get_alternative_types<LL, LR, C>::type left;
193 typedef typename get_alternative_types<RL, RR, C>::type right;
194 typedef typename
195 mpl::insert_range<left, typename mpl::end<left>::type, right>::type
196 type;
197 };
198
199 template <typename L, typename R, typename C>
200 struct attribute_of_alternative
201 {
202 // Get all alternative attribute types
203 typedef typename get_alternative_types<L, R, C>::type all_types;
204
205 // Filter all unused_types
206 typedef typename
207 mpl::copy_if<
208 all_types
209 , mpl::not_<is_same<mpl::_1, unused_type>>
210 , mpl::back_inserter<mpl::vector<>>
211 >::type
212 filtered_types;
213
214 // Build a variant if filtered_types is not empty,
215 // else just return unused_type
216 typedef typename
217 mpl::eval_if<
218 mpl::empty<filtered_types>
219 , mpl::identity<unused_type>
220 , make_variant_over<filtered_types>
221 >::type
222 type;
223 };
224
225 template <typename IsAlternative>
226 struct move_if_not_alternative
227 {
228 template<typename T1, typename T2>
229 static void call(T1& attr_, T2& attr) {}
230 };
231
232 template <>
233 struct move_if_not_alternative<mpl::false_ /*is alternative*/>
234 {
235 template<typename T1, typename T2>
236 static void call(T1& attr_, T2& attr)
237 {
238 traits::move_to(attr_, attr);
239 }
240 };
241
242 template <typename Parser, typename Iterator, typename Context
243 , typename RContext, typename Attribute>
244 bool parse_alternative(Parser const& p, Iterator& first, Iterator const& last
245 , Context const& context, RContext& rcontext, Attribute& attr)
246 {
247 typedef detail::pass_variant_attribute<Parser, Attribute, Context> pass;
248
249 typename pass::type attr_ = pass::call(attr);
250 if (p.parse(first, last, context, rcontext, attr_))
251 {
252 move_if_not_alternative<typename pass::is_alternative>::call(attr_, attr);
253 return true;
254 }
255 return false;
256 }
257
258
259 template <typename Left, typename Right, typename Context, typename RContext>
260 struct parse_into_container_impl<alternative<Left, Right>, Context, RContext>
261 {
262 typedef alternative<Left, Right> parser_type;
263
264 template <typename Iterator, typename Attribute>
265 static bool call(
266 parser_type const& parser
267 , Iterator& first, Iterator const& last
268 , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
269 {
270 return parse_alternative(parser, first, last, context, rcontext, attr);
271 }
272
273 template <typename Iterator, typename Attribute>
274 static bool call(
275 parser_type const& parser
276 , Iterator& first, Iterator const& last
277 , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
278 {
279 return parse_into_container_base_impl<parser_type>::call(
280 parser, first, last, context, rcontext, attr);
281 }
282
283 template <typename Iterator, typename Attribute>
284 static bool call(
285 parser_type const& parser
286 , Iterator& first, Iterator const& last
287 , Context const& context, RContext& rcontext, Attribute& attr)
288 {
289 typedef typename
290 traits::attribute_of<parser_type, Context>::type
291 attribute_type;
292
293 return call(parser, first, last, context, rcontext, attr
294 , traits::variant_has_substitute<attribute_type, Attribute>());
295 }
296 };
297
298 }}}}
299
300 #endif