]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/spirit/home/x3/operator/detail/sequence.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / spirit / home / x3 / operator / detail / sequence.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(BOOST_SPIRIT_X3_SEQUENCE_DETAIL_JAN_06_2013_1015AM)
8 #define BOOST_SPIRIT_X3_SEQUENCE_DETAIL_JAN_06_2013_1015AM
9
10 #include <boost/spirit/home/x3/support/traits/attribute_of.hpp>
11 #include <boost/spirit/home/x3/support/traits/attribute_category.hpp>
12 #include <boost/spirit/home/x3/support/traits/has_attribute.hpp>
13 #include <boost/spirit/home/x3/support/traits/is_substitute.hpp>
14 #include <boost/spirit/home/x3/support/traits/container_traits.hpp>
15 #include <boost/spirit/home/x3/support/traits/tuple_traits.hpp>
16 #include <boost/spirit/home/x3/core/detail/parse_into_container.hpp>
17
18 #include <boost/fusion/include/begin.hpp>
19 #include <boost/fusion/include/end.hpp>
20 #include <boost/fusion/include/advance.hpp>
21 #include <boost/fusion/include/deref.hpp>
22 #include <boost/fusion/include/empty.hpp>
23 #include <boost/fusion/include/front.hpp>
24 #include <boost/fusion/include/iterator_range.hpp>
25 #include <boost/fusion/include/as_deque.hpp>
26 #include <boost/fusion/include/mpl.hpp>
27
28 #include <boost/mpl/copy_if.hpp>
29 #include <boost/mpl/not.hpp>
30 #include <boost/mpl/if.hpp>
31 #include <boost/mpl/insert_range.hpp>
32 #include <boost/mpl/eval_if.hpp>
33 #include <boost/mpl/vector.hpp>
34 #include <boost/mpl/identity.hpp>
35
36 #include <boost/type_traits/add_reference.hpp>
37 #include <boost/type_traits/is_same.hpp>
38
39 #include <iterator> // for std::make_move_iterator
40
41 namespace boost { namespace spirit { namespace x3
42 {
43 template <typename Left, typename Right>
44 struct sequence;
45 }}}
46
47 namespace boost { namespace spirit { namespace x3 { namespace detail
48 {
49 template <typename Parser, typename Context, typename Enable = void>
50 struct sequence_size
51 {
52 static int const value = traits::has_attribute<Parser, Context>::value;
53 };
54
55 template <typename Parser, typename Context>
56 struct sequence_size_subject
57 : sequence_size<typename Parser::subject_type, Context> {};
58
59 template <typename Parser, typename Context>
60 struct sequence_size<Parser, Context
61 , typename enable_if_c<(Parser::is_pass_through_unary)>::type>
62 : sequence_size_subject<Parser, Context> {};
63
64 template <typename L, typename R, typename Context>
65 struct sequence_size<sequence<L, R>, Context>
66 {
67 static int const value =
68 sequence_size<L, Context>::value +
69 sequence_size<R, Context>::value;
70 };
71
72 struct pass_sequence_attribute_unused
73 {
74 typedef unused_type type;
75
76 template <typename T>
77 static unused_type
78 call(T&)
79 {
80 return unused_type();
81 }
82 };
83
84 template <typename Attribute>
85 struct pass_sequence_attribute_size_one_view
86 {
87 typedef typename fusion::result_of::deref<
88 typename fusion::result_of::begin<Attribute>::type
89 >::type type;
90
91 static type call(Attribute& attr)
92 {
93 return fusion::deref(fusion::begin(attr));
94 }
95 };
96
97 template <typename Attribute>
98 struct pass_through_sequence_attribute
99 {
100 typedef Attribute& type;
101
102 template <typename Attribute_>
103 static Attribute_&
104 call(Attribute_& attr)
105 {
106 return attr;
107 }
108 };
109
110 template <typename Parser, typename Attribute, typename Enable = void>
111 struct pass_sequence_attribute :
112 mpl::if_<
113 traits::is_size_one_view<Attribute>
114 , pass_sequence_attribute_size_one_view<Attribute>
115 , pass_through_sequence_attribute<Attribute>>::type {};
116
117 template <typename L, typename R, typename Attribute>
118 struct pass_sequence_attribute<sequence<L, R>, Attribute>
119 : pass_through_sequence_attribute<Attribute> {};
120
121 template <typename Parser, typename Attribute>
122 struct pass_sequence_attribute_subject :
123 pass_sequence_attribute<typename Parser::subject_type, Attribute> {};
124
125 template <typename Parser, typename Attribute>
126 struct pass_sequence_attribute<Parser, Attribute
127 , typename enable_if_c<(Parser::is_pass_through_unary)>::type>
128 : pass_sequence_attribute_subject<Parser, Attribute> {};
129
130 template <typename L, typename R, typename Attribute, typename Context
131 , typename Enable = void>
132 struct partition_attribute
133 {
134 using attr_category = typename traits::attribute_category<Attribute>::type;
135 static_assert(is_same<traits::tuple_attribute, attr_category>::value,
136 "The parser expects tuple-like attribute type");
137
138 static int const l_size = sequence_size<L, Context>::value;
139 static int const r_size = sequence_size<R, Context>::value;
140
141 static int constexpr actual_size = fusion::result_of::size<Attribute>::value;
142 static int constexpr expected_size = l_size + r_size;
143
144 // If you got an error here, then you are trying to pass
145 // a fusion sequence with the wrong number of elements
146 // as that expected by the (sequence) parser.
147 static_assert(
148 actual_size >= expected_size
149 , "Size of the passed attribute is less than expected."
150 );
151 static_assert(
152 actual_size <= expected_size
153 , "Size of the passed attribute is bigger than expected."
154 );
155
156 typedef typename fusion::result_of::begin<Attribute>::type l_begin;
157 typedef typename fusion::result_of::advance_c<l_begin, l_size>::type l_end;
158 typedef typename fusion::result_of::end<Attribute>::type r_end;
159 typedef fusion::iterator_range<l_begin, l_end> l_part;
160 typedef fusion::iterator_range<l_end, r_end> r_part;
161 typedef pass_sequence_attribute<L, l_part> l_pass;
162 typedef pass_sequence_attribute<R, r_part> r_pass;
163
164 static l_part left(Attribute& s)
165 {
166 auto i = fusion::begin(s);
167 return l_part(i, fusion::advance_c<l_size>(i));
168 }
169
170 static r_part right(Attribute& s)
171 {
172 return r_part(
173 fusion::advance_c<l_size>(fusion::begin(s))
174 , fusion::end(s));
175 }
176 };
177
178 template <typename L, typename R, typename Attribute, typename Context>
179 struct partition_attribute<L, R, Attribute, Context,
180 typename enable_if_c<(!traits::has_attribute<L, Context>::value &&
181 traits::has_attribute<R, Context>::value)>::type>
182 {
183 typedef unused_type l_part;
184 typedef Attribute& r_part;
185 typedef pass_sequence_attribute_unused l_pass;
186 typedef pass_sequence_attribute<R, Attribute> r_pass;
187
188 static unused_type left(Attribute&)
189 {
190 return unused;
191 }
192
193 static Attribute& right(Attribute& s)
194 {
195 return s;
196 }
197 };
198
199 template <typename L, typename R, typename Attribute, typename Context>
200 struct partition_attribute<L, R, Attribute, Context,
201 typename enable_if_c<(traits::has_attribute<L, Context>::value &&
202 !traits::has_attribute<R, Context>::value)>::type>
203 {
204 typedef Attribute& l_part;
205 typedef unused_type r_part;
206 typedef pass_sequence_attribute<L, Attribute> l_pass;
207 typedef pass_sequence_attribute_unused r_pass;
208
209 static Attribute& left(Attribute& s)
210 {
211 return s;
212 }
213
214 static unused_type right(Attribute&)
215 {
216 return unused;
217 }
218 };
219
220 template <typename L, typename R, typename Attribute, typename Context>
221 struct partition_attribute<L, R, Attribute, Context,
222 typename enable_if_c<(!traits::has_attribute<L, Context>::value &&
223 !traits::has_attribute<R, Context>::value)>::type>
224 {
225 typedef unused_type l_part;
226 typedef unused_type r_part;
227 typedef pass_sequence_attribute_unused l_pass;
228 typedef pass_sequence_attribute_unused r_pass;
229
230 static unused_type left(Attribute&)
231 {
232 return unused;
233 }
234
235 static unused_type right(Attribute&)
236 {
237 return unused;
238 }
239 };
240
241 template <typename L, typename R, typename C>
242 struct get_sequence_types
243 {
244 typedef
245 mpl::vector<
246 typename traits::attribute_of<L, C>::type
247 , typename traits::attribute_of<R, C>::type
248 >
249 type;
250 };
251
252 template <typename LL, typename LR, typename R, typename C>
253 struct get_sequence_types<sequence<LL, LR>, R, C>
254 : mpl::push_back< typename get_sequence_types<LL, LR, C>::type
255 , typename traits::attribute_of<R, C>::type> {};
256
257 template <typename L, typename RL, typename RR, typename C>
258 struct get_sequence_types<L, sequence<RL, RR>, C>
259 : mpl::push_front< typename get_sequence_types<RL, RR, C>::type
260 , typename traits::attribute_of<L, C>::type> {};
261
262 template <typename LL, typename LR, typename RL, typename RR, typename C>
263 struct get_sequence_types<sequence<LL, LR>, sequence<RL, RR>, C>
264 {
265 typedef typename get_sequence_types<LL, LR, C>::type left;
266 typedef typename get_sequence_types<RL, RR, C>::type right;
267 typedef typename
268 mpl::insert_range<left, typename mpl::end<left>::type, right>::type
269 type;
270 };
271
272 template <typename L, typename R, typename C>
273 struct attribute_of_sequence
274 {
275 // Get all sequence attribute types
276 typedef typename get_sequence_types<L, R, C>::type all_types;
277
278 // Filter all unused_types
279 typedef typename
280 mpl::copy_if<
281 all_types
282 , mpl::not_<is_same<mpl::_1, unused_type>>
283 , mpl::back_inserter<mpl::vector<>>
284 >::type
285 filtered_types;
286
287 // Build a fusion::deque if filtered_types is not empty,
288 // else just return unused_type
289 typedef typename
290 mpl::eval_if<
291 mpl::empty<filtered_types>
292 , mpl::identity<unused_type>
293 , mpl::if_<mpl::equal_to<mpl::size<filtered_types>, mpl::int_<1> >,
294 typename mpl::front<filtered_types>::type
295 , typename fusion::result_of::as_deque<filtered_types>::type >
296 >::type
297 type;
298 };
299
300 template <typename Parser, typename Iterator, typename Context
301 , typename RContext, typename Attribute, typename AttributeCategory>
302 bool parse_sequence(
303 Parser const& parser, Iterator& first, Iterator const& last
304 , Context const& context, RContext& rcontext, Attribute& attr
305 , AttributeCategory)
306 {
307 using Left = typename Parser::left_type;
308 using Right = typename Parser::right_type;
309 using partition = partition_attribute<Left, Right, Attribute, Context>;
310 using l_pass = typename partition::l_pass;
311 using r_pass = typename partition::r_pass;
312
313 typename partition::l_part l_part = partition::left(attr);
314 typename partition::r_part r_part = partition::right(attr);
315 typename l_pass::type l_attr = l_pass::call(l_part);
316 typename r_pass::type r_attr = r_pass::call(r_part);
317
318 Iterator save = first;
319 if (parser.left.parse(first, last, context, rcontext, l_attr)
320 && parser.right.parse(first, last, context, rcontext, r_attr))
321 return true;
322 first = save;
323 return false;
324 }
325
326 template <typename Parser, typename Context>
327 constexpr bool pass_sequence_container_attribute
328 = sequence_size<Parser, Context>::value > 1;
329
330 template <typename Parser, typename Iterator, typename Context
331 , typename RContext, typename Attribute>
332 typename enable_if_c<pass_sequence_container_attribute<Parser, Context>, bool>::type
333 parse_sequence_container(
334 Parser const& parser
335 , Iterator& first, Iterator const& last, Context const& context
336 , RContext& rcontext, Attribute& attr)
337 {
338 return parser.parse(first, last, context, rcontext, attr);
339 }
340
341 template <typename Parser, typename Iterator, typename Context
342 , typename RContext, typename Attribute>
343 typename disable_if_c<pass_sequence_container_attribute<Parser, Context>, bool>::type
344 parse_sequence_container(
345 Parser const& parser
346 , Iterator& first, Iterator const& last, Context const& context
347 , RContext& rcontext, Attribute& attr)
348 {
349 return parse_into_container(parser, first, last, context, rcontext, attr);
350 }
351
352 template <typename Parser, typename Iterator, typename Context
353 , typename RContext, typename Attribute>
354 bool parse_sequence(
355 Parser const& parser , Iterator& first, Iterator const& last
356 , Context const& context, RContext& rcontext, Attribute& attr
357 , traits::container_attribute)
358 {
359 Iterator save = first;
360 if (parse_sequence_container(parser.left, first, last, context, rcontext, attr)
361 && parse_sequence_container(parser.right, first, last, context, rcontext, attr))
362 return true;
363 first = save;
364 return false;
365 }
366
367 template <typename Parser, typename Iterator, typename Context
368 , typename RContext, typename Attribute>
369 bool parse_sequence_assoc(
370 Parser const& parser , Iterator& first, Iterator const& last
371 , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_ /*should_split*/)
372 {
373 return parse_into_container(parser, first, last, context, rcontext, attr);
374 }
375
376 template <typename Parser, typename Iterator, typename Context
377 , typename RContext, typename Attribute>
378 bool parse_sequence_assoc(
379 Parser const& parser , Iterator& first, Iterator const& last
380 , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_ /*should_split*/)
381 {
382 Iterator save = first;
383 if (parser.left.parse( first, last, context, rcontext, attr)
384 && parser.right.parse(first, last, context, rcontext, attr))
385 return true;
386 first = save;
387 return false;
388 }
389
390 template <typename Parser, typename Iterator, typename Context
391 , typename RContext, typename Attribute>
392 bool parse_sequence(
393 Parser const& parser, Iterator& first, Iterator const& last
394 , Context const& context, RContext& rcontext, Attribute& attr
395 , traits::associative_attribute)
396 {
397 // we can come here in 2 cases:
398 // - when sequence is key >> value and therefore must
399 // be parsed with tuple synthesized attribute and then
400 // that tuple is used to save into associative attribute provided here.
401 // Example: key >> value;
402 //
403 // - when either this->left or this->right provides full key-value
404 // pair (like in case 1) and another one provides nothing.
405 // Example: eps >> rule<class x; fusion::map<...> >
406 //
407 // first case must be parsed as whole, and second one should
408 // be parsed separately for left and right.
409
410 typedef typename traits::attribute_of<
411 decltype(parser.left), Context>::type l_attr_type;
412 typedef typename traits::attribute_of<
413 decltype(parser.right), Context>::type r_attr_type;
414
415 typedef typename
416 mpl::or_<
417 is_same<l_attr_type, unused_type>
418 , is_same<r_attr_type, unused_type> >
419 should_split;
420
421 return parse_sequence_assoc(parser, first, last, context, rcontext, attr
422 , should_split());
423 }
424
425 template <typename Left, typename Right, typename Context, typename RContext>
426 struct parse_into_container_impl<sequence<Left, Right>, Context, RContext>
427 {
428 typedef sequence<Left, Right> parser_type;
429
430 template <typename Iterator, typename Attribute>
431 static bool call(
432 parser_type const& parser
433 , Iterator& first, Iterator const& last
434 , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
435 {
436 // inform user what went wrong if we jumped here in attempt to
437 // parse incompatible sequence into fusion::map
438 static_assert(!is_same< typename traits::attribute_category<Attribute>::type,
439 traits::associative_attribute>::value,
440 "To parse directly into fusion::map sequence must produce tuple attribute "
441 "where type of first element is existing key in fusion::map and second element "
442 "is value to be stored under that key");
443
444 Attribute attr_;
445 if (!parse_sequence(parser
446 , first, last, context, rcontext, attr_, traits::container_attribute()))
447 {
448 return false;
449 }
450 traits::append(attr, std::make_move_iterator(traits::begin(attr_)),
451 std::make_move_iterator(traits::end(attr_)));
452 return true;
453 }
454
455 template <typename Iterator, typename Attribute>
456 static bool call(
457 parser_type const& parser
458 , Iterator& first, Iterator const& last
459 , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
460 {
461 return parse_into_container_base_impl<parser_type>::call(
462 parser, first, last, context, rcontext, attr);
463 }
464
465 template <typename Iterator, typename Attribute>
466 static bool call(
467 parser_type const& parser
468 , Iterator& first, Iterator const& last
469 , Context const& context, RContext& rcontext, Attribute& attr)
470 {
471 typedef typename
472 traits::attribute_of<parser_type, Context>::type
473 attribute_type;
474
475 typedef typename
476 traits::container_value<Attribute>::type
477 value_type;
478
479 return call(parser, first, last, context, rcontext, attr
480 , typename traits::is_substitute<attribute_type, value_type>::type());
481 }
482 };
483
484 }}}}
485
486 #endif