]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Copyright (c) 2001-2011 Joel de Guzman | |
3 | Copyright (c) 2001-2012 Hartmut Kaiser | |
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_ATTRIBUTES_JANUARY_29_2007_0954AM) | |
9 | #define BOOST_SPIRIT_ATTRIBUTES_JANUARY_29_2007_0954AM | |
10 | ||
11 | #if defined(_MSC_VER) | |
12 | #pragma once | |
13 | #endif | |
14 | ||
15 | #include <boost/spirit/home/support/unused.hpp> | |
16 | #include <boost/spirit/home/support/has_semantic_action.hpp> | |
17 | #include <boost/spirit/home/support/attributes_fwd.hpp> | |
18 | #include <boost/spirit/home/support/container.hpp> | |
19 | #include <boost/spirit/home/support/detail/hold_any.hpp> | |
20 | #include <boost/spirit/home/support/detail/as_variant.hpp> | |
21 | #include <boost/optional/optional.hpp> | |
22 | #include <boost/fusion/include/transform.hpp> | |
23 | #include <boost/fusion/include/filter_if.hpp> | |
24 | #include <boost/fusion/include/as_vector.hpp> | |
25 | #include <boost/fusion/include/push_front.hpp> | |
26 | #include <boost/fusion/include/pop_front.hpp> | |
27 | #include <boost/fusion/include/is_sequence.hpp> | |
28 | #include <boost/fusion/include/for_each.hpp> | |
29 | #include <boost/fusion/include/is_view.hpp> | |
30 | #include <boost/fusion/include/mpl.hpp> | |
7c673cae FG |
31 | #include <boost/type_traits/is_same.hpp> |
32 | #include <boost/type_traits/is_convertible.hpp> | |
92f5a8d4 | 33 | #include <boost/type_traits/is_reference.hpp> |
7c673cae FG |
34 | #include <boost/mpl/eval_if.hpp> |
35 | #include <boost/mpl/end.hpp> | |
36 | #include <boost/mpl/find_if.hpp> | |
37 | #include <boost/mpl/identity.hpp> | |
38 | #include <boost/mpl/deref.hpp> | |
39 | #include <boost/mpl/distance.hpp> | |
40 | #include <boost/mpl/or.hpp> | |
41 | #include <boost/mpl/has_xxx.hpp> | |
42 | #include <boost/mpl/equal.hpp> | |
f67539c2 | 43 | #include <boost/proto/traits.hpp> |
7c673cae FG |
44 | #include <boost/utility/enable_if.hpp> |
45 | #include <boost/variant.hpp> | |
46 | #include <boost/range/iterator_range.hpp> | |
47 | #include <boost/config.hpp> | |
92f5a8d4 | 48 | #include <iterator> // for std::iterator_traits, std::distance |
7c673cae FG |
49 | #include <vector> |
50 | #include <utility> | |
51 | #include <ios> | |
52 | ||
53 | /////////////////////////////////////////////////////////////////////////////// | |
54 | namespace boost { namespace spirit { namespace traits | |
55 | { | |
56 | /////////////////////////////////////////////////////////////////////////// | |
57 | // This file deals with attribute related functions and meta-functions | |
58 | // including generalized attribute transformation utilities for Spirit | |
59 | // components. | |
60 | /////////////////////////////////////////////////////////////////////////// | |
61 | ||
62 | /////////////////////////////////////////////////////////////////////////// | |
63 | // Find out if T can be a (strong) substitute for Expected attribute | |
64 | namespace detail | |
65 | { | |
66 | template <typename T, typename Expected> | |
67 | struct value_type_is_substitute | |
68 | : is_substitute< | |
69 | typename container_value<T>::type | |
70 | , typename container_value<Expected>::type> | |
71 | {}; | |
72 | ||
73 | template <typename T, typename Expected, typename Enable = void> | |
74 | struct is_substitute_impl : is_same<T, Expected> {}; | |
75 | ||
76 | template <typename T, typename Expected> | |
77 | struct is_substitute_impl<T, Expected, | |
78 | typename enable_if< | |
79 | mpl::and_< | |
80 | fusion::traits::is_sequence<T>, | |
81 | fusion::traits::is_sequence<Expected>, | |
82 | mpl::equal<T, Expected, is_substitute<mpl::_1, mpl::_2> > | |
83 | > | |
84 | >::type> | |
85 | : mpl::true_ {}; | |
86 | ||
87 | template <typename T, typename Expected> | |
88 | struct is_substitute_impl<T, Expected, | |
89 | typename enable_if< | |
90 | mpl::and_< | |
91 | is_container<T>, | |
92 | is_container<Expected>, | |
93 | detail::value_type_is_substitute<T, Expected> | |
94 | > | |
95 | >::type> | |
96 | : mpl::true_ {}; | |
97 | } | |
98 | ||
99 | template <typename T, typename Expected, typename Enable /*= void*/> | |
100 | struct is_substitute | |
101 | : detail::is_substitute_impl<T, Expected> {}; | |
102 | ||
103 | template <typename T, typename Expected> | |
104 | struct is_substitute<optional<T>, optional<Expected> > | |
105 | : is_substitute<T, Expected> {}; | |
106 | ||
107 | template <typename T> | |
108 | struct is_substitute<T, T | |
109 | , typename enable_if<not_is_optional<T> >::type> | |
110 | : mpl::true_ {}; | |
111 | ||
112 | /////////////////////////////////////////////////////////////////////////// | |
113 | // Find out if T can be a weak substitute for Expected attribute | |
114 | namespace detail | |
115 | { | |
116 | // A type, which is convertible to the attribute is at the same time | |
117 | // usable as its weak substitute. | |
118 | template <typename T, typename Expected, typename Enable = void> | |
119 | struct is_weak_substitute_impl : is_convertible<T, Expected> {}; | |
120 | ||
121 | // // An exposed attribute is a weak substitute for a supplied container | |
122 | // // attribute if it is a weak substitute for its value_type. This is | |
123 | // // true as all character parsers are compatible with a container | |
124 | // // attribute having the corresponding character type as its value_type. | |
125 | // template <typename T, typename Expected> | |
126 | // struct is_weak_substitute_for_value_type | |
127 | // : is_weak_substitute<T, typename container_value<Expected>::type> | |
128 | // {}; | |
129 | // | |
130 | // template <typename T, typename Expected> | |
131 | // struct is_weak_substitute_impl<T, Expected, | |
132 | // typename enable_if< | |
133 | // mpl::and_< | |
134 | // mpl::not_<is_string<T> > | |
135 | // , is_string<Expected> | |
136 | // , is_weak_substitute_for_value_type<T, Expected> > | |
137 | // >::type> | |
138 | // : mpl::true_ | |
139 | // {}; | |
140 | ||
141 | // An exposed container attribute is a weak substitute for a supplied | |
142 | // container attribute if and only if their value_types are weak | |
143 | // substitutes. | |
144 | template <typename T, typename Expected> | |
145 | struct value_type_is_weak_substitute | |
146 | : is_weak_substitute< | |
147 | typename container_value<T>::type | |
148 | , typename container_value<Expected>::type> | |
149 | {}; | |
150 | ||
151 | template <typename T, typename Expected> | |
152 | struct is_weak_substitute_impl<T, Expected, | |
153 | typename enable_if< | |
154 | mpl::and_< | |
155 | is_container<T> | |
156 | , is_container<Expected> | |
157 | , value_type_is_weak_substitute<T, Expected> > | |
158 | >::type> | |
159 | : mpl::true_ {}; | |
160 | ||
161 | // Two fusion sequences are weak substitutes if and only if their | |
162 | // elements are pairwise weak substitutes. | |
163 | template <typename T, typename Expected> | |
164 | struct is_weak_substitute_impl<T, Expected, | |
165 | typename enable_if< | |
166 | mpl::and_< | |
167 | fusion::traits::is_sequence<T> | |
168 | , fusion::traits::is_sequence<Expected> | |
169 | , mpl::equal<T, Expected, is_weak_substitute<mpl::_1, mpl::_2> > > | |
170 | >::type> | |
171 | : mpl::true_ {}; | |
172 | ||
173 | // If this is not defined, the main template definition above will return | |
174 | // true if T is convertible to the first type in a fusion::vector. We | |
175 | // globally declare any non-Fusion sequence T as not compatible with any | |
176 | // Fusion sequence 'Expected'. | |
177 | template <typename T, typename Expected> | |
178 | struct is_weak_substitute_impl<T, Expected, | |
179 | typename enable_if< | |
180 | mpl::and_< | |
181 | mpl::not_<fusion::traits::is_sequence<T> > | |
182 | , fusion::traits::is_sequence<Expected> > | |
183 | >::type> | |
184 | : mpl::false_ {}; | |
185 | } | |
186 | ||
187 | // main template forwards to detail namespace, this helps older compilers | |
188 | // to disambiguate things | |
189 | template <typename T, typename Expected, typename Enable /*= void*/> | |
190 | struct is_weak_substitute | |
191 | : detail::is_weak_substitute_impl<T, Expected> {}; | |
192 | ||
193 | template <typename T, typename Expected> | |
194 | struct is_weak_substitute<optional<T>, optional<Expected> > | |
195 | : is_weak_substitute<T, Expected> {}; | |
196 | ||
197 | template <typename T, typename Expected> | |
198 | struct is_weak_substitute<optional<T>, Expected> | |
199 | : is_weak_substitute<T, Expected> {}; | |
200 | ||
201 | template <typename T, typename Expected> | |
202 | struct is_weak_substitute<T, optional<Expected> > | |
203 | : is_weak_substitute<T, Expected> {}; | |
204 | ||
205 | #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) | |
206 | template <typename T, typename Expected> | |
207 | struct is_weak_substitute<boost::variant<T>, Expected> | |
208 | : is_weak_substitute<T, Expected> | |
209 | {}; | |
210 | ||
211 | template <typename T0, typename T1, typename ...TN, typename Expected> | |
212 | struct is_weak_substitute<boost::variant<T0, T1, TN...>, | |
213 | Expected> | |
214 | : mpl::bool_<is_weak_substitute<T0, Expected>::type::value && | |
215 | is_weak_substitute<boost::variant<T1, TN...>, Expected>::type::value> | |
216 | {}; | |
217 | #else | |
218 | #define BOOST_SPIRIT_IS_WEAK_SUBSTITUTE(z, N, _) \ | |
219 | is_weak_substitute<BOOST_PP_CAT(T, N), Expected>::type::value && \ | |
220 | /***/ | |
221 | ||
222 | // make sure unused variant parameters do not affect the outcome | |
223 | template <typename Expected> | |
224 | struct is_weak_substitute<boost::detail::variant::void_, Expected> | |
225 | : mpl::true_ | |
226 | {}; | |
227 | ||
228 | template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Expected> | |
229 | struct is_weak_substitute< | |
230 | boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Expected> | |
231 | : mpl::bool_<BOOST_PP_REPEAT(BOOST_VARIANT_LIMIT_TYPES | |
232 | , BOOST_SPIRIT_IS_WEAK_SUBSTITUTE, _) true> | |
233 | {}; | |
234 | ||
235 | #undef BOOST_SPIRIT_IS_WEAK_SUBSTITUTE | |
236 | #endif | |
237 | ||
238 | template <typename T> | |
239 | struct is_weak_substitute<T, T | |
240 | , typename enable_if< | |
241 | mpl::and_<not_is_optional<T>, not_is_variant<T> > | |
242 | >::type> | |
243 | : mpl::true_ {}; | |
244 | ||
245 | /////////////////////////////////////////////////////////////////////////// | |
246 | template <typename T, typename Enable/* = void*/> | |
247 | struct is_proxy : mpl::false_ {}; | |
248 | ||
249 | template <typename T> | |
250 | struct is_proxy<T, | |
251 | typename enable_if< | |
252 | mpl::and_< | |
253 | fusion::traits::is_sequence<T>, | |
254 | fusion::traits::is_view<T> | |
255 | > | |
256 | >::type> | |
257 | : mpl::true_ {}; | |
258 | ||
259 | namespace detail | |
260 | { | |
261 | // By declaring a nested struct in your class/struct, you tell | |
262 | // spirit that it is regarded as a variant type. The minimum | |
263 | // required interface for such a variant is that it has constructors | |
264 | // for various types supported by your variant and a typedef 'types' | |
265 | // which is an mpl sequence of the contained types. | |
266 | // | |
267 | // This is an intrusive interface. For a non-intrusive interface, | |
268 | // use the not_is_variant trait. | |
269 | BOOST_MPL_HAS_XXX_TRAIT_DEF(adapted_variant_tag) | |
270 | } | |
271 | ||
272 | template <typename T, typename Domain, typename Enable/* = void*/> | |
273 | struct not_is_variant | |
274 | : mpl::not_<detail::has_adapted_variant_tag<T> > | |
275 | {}; | |
276 | ||
277 | template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Domain> | |
278 | struct not_is_variant<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Domain> | |
279 | : mpl::false_ | |
280 | {}; | |
281 | ||
7c673cae FG |
282 | // we treat every type as if it where the variant (as this meta function is |
283 | // invoked for variant types only) | |
284 | template <typename T> | |
285 | struct variant_type | |
286 | : mpl::identity<T> | |
287 | {}; | |
288 | ||
289 | template <typename T> | |
290 | struct variant_type<boost::optional<T> > | |
291 | : variant_type<T> | |
292 | {}; | |
293 | ||
11fdf7f2 TL |
294 | template <typename T, typename Domain> |
295 | struct not_is_variant_or_variant_in_optional | |
296 | : not_is_variant<typename variant_type<T>::type, Domain> | |
297 | {}; | |
298 | ||
7c673cae FG |
299 | /////////////////////////////////////////////////////////////////////////// |
300 | // The compute_compatible_component_variant | |
301 | /////////////////////////////////////////////////////////////////////////// | |
302 | namespace detail | |
303 | { | |
304 | // A component is compatible to a given Attribute type if the | |
305 | // Attribute is the same as the expected type of the component or if | |
306 | // it is convertible to the expected type. | |
307 | template <typename Expected, typename Attribute> | |
308 | struct attribute_is_compatible | |
309 | : is_convertible<Attribute, Expected> | |
310 | {}; | |
311 | ||
312 | template <typename Expected, typename Attribute> | |
313 | struct attribute_is_compatible<Expected, boost::optional<Attribute> > | |
314 | : is_convertible<Attribute, Expected> | |
315 | {}; | |
316 | ||
317 | template <typename Container> | |
318 | struct is_hold_any_container | |
319 | : traits::is_hold_any<typename traits::container_value<Container>::type> | |
320 | {}; | |
321 | } | |
322 | ||
323 | template <typename Attribute, typename Expected | |
324 | , typename IsNotVariant = mpl::false_, typename Enable = void> | |
325 | struct compute_compatible_component_variant | |
326 | : mpl::or_< | |
327 | traits::detail::attribute_is_compatible<Expected, Attribute> | |
328 | , traits::is_hold_any<Expected> | |
329 | , mpl::eval_if< | |
330 | is_container<Expected> | |
331 | , traits::detail::is_hold_any_container<Expected> | |
332 | , mpl::false_> > | |
333 | {}; | |
334 | ||
335 | namespace detail | |
336 | { | |
337 | BOOST_MPL_HAS_XXX_TRAIT_DEF(types) | |
338 | } | |
339 | ||
340 | template <typename Variant, typename Expected> | |
341 | struct compute_compatible_component_variant<Variant, Expected, mpl::false_ | |
11fdf7f2 | 342 | , typename enable_if<detail::has_types<typename variant_type<Variant>::type> >::type> |
7c673cae FG |
343 | { |
344 | typedef typename traits::variant_type<Variant>::type variant_type; | |
345 | typedef typename variant_type::types types; | |
346 | typedef typename mpl::end<types>::type end; | |
347 | ||
348 | typedef typename | |
349 | mpl::find_if<types, is_same<Expected, mpl::_1> >::type | |
350 | iter; | |
351 | ||
352 | typedef typename mpl::distance< | |
353 | typename mpl::begin<types>::type, iter | |
354 | >::type distance; | |
355 | ||
356 | // true_ if the attribute matches one of the types in the variant | |
357 | typedef typename mpl::not_<is_same<iter, end> >::type type; | |
358 | enum { value = type::value }; | |
359 | ||
360 | // return the type in the variant the attribute is compatible with | |
361 | typedef typename | |
362 | mpl::eval_if<type, mpl::deref<iter>, mpl::identity<unused_type> >::type | |
363 | compatible_type; | |
364 | ||
365 | // return whether the given type is compatible with the Expected type | |
366 | static bool is_compatible(int which) | |
367 | { | |
368 | return which == distance::value; | |
369 | } | |
370 | }; | |
371 | ||
372 | template <typename Expected, typename Attribute, typename Domain> | |
373 | struct compute_compatible_component | |
374 | : compute_compatible_component_variant<Attribute, Expected | |
11fdf7f2 | 375 | , typename not_is_variant_or_variant_in_optional<Attribute, Domain>::type> {}; |
7c673cae FG |
376 | |
377 | template <typename Expected, typename Domain> | |
378 | struct compute_compatible_component<Expected, unused_type, Domain> | |
379 | : mpl::false_ {}; | |
380 | ||
381 | template <typename Attribute, typename Domain> | |
382 | struct compute_compatible_component<unused_type, Attribute, Domain> | |
383 | : mpl::false_ {}; | |
384 | ||
385 | template <typename Domain> | |
386 | struct compute_compatible_component<unused_type, unused_type, Domain> | |
387 | : mpl::false_ {}; | |
388 | ||
389 | /////////////////////////////////////////////////////////////////////////// | |
390 | // return the type currently stored in the given variant | |
391 | template <BOOST_VARIANT_ENUM_PARAMS(typename T)> | |
392 | struct variant_which<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > | |
393 | { | |
394 | static int call(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& v) | |
395 | { | |
396 | return v.which(); | |
397 | } | |
398 | }; | |
399 | ||
400 | template <typename T> | |
401 | int which(T const& v) | |
402 | { | |
403 | return variant_which<T>::call(v); | |
404 | } | |
405 | ||
406 | /////////////////////////////////////////////////////////////////////////// | |
407 | template <typename T, typename Domain, typename Enable/* = void*/> | |
408 | struct not_is_optional | |
409 | : mpl::true_ | |
410 | {}; | |
411 | ||
412 | template <typename T, typename Domain> | |
413 | struct not_is_optional<boost::optional<T>, Domain> | |
414 | : mpl::false_ | |
415 | {}; | |
416 | ||
417 | /////////////////////////////////////////////////////////////////////////// | |
418 | // attribute_of | |
419 | // | |
420 | // Get the component's attribute | |
421 | /////////////////////////////////////////////////////////////////////////// | |
422 | template <typename Component | |
423 | , typename Context = unused_type, typename Iterator = unused_type> | |
424 | struct attribute_of | |
425 | { | |
426 | typedef typename Component::template | |
427 | attribute<Context, Iterator>::type type; | |
428 | }; | |
429 | ||
430 | /////////////////////////////////////////////////////////////////////////// | |
431 | // attribute_not_unused | |
432 | // | |
433 | // An mpl meta-function class that determines whether a component's | |
434 | // attribute is not unused. | |
435 | /////////////////////////////////////////////////////////////////////////// | |
436 | template <typename Context, typename Iterator = unused_type> | |
437 | struct attribute_not_unused | |
438 | { | |
439 | template <typename Component> | |
440 | struct apply | |
441 | : not_is_unused<typename | |
442 | attribute_of<Component, Context, Iterator>::type> | |
443 | {}; | |
444 | }; | |
445 | ||
446 | /////////////////////////////////////////////////////////////////////////// | |
447 | // Retrieve the attribute type to use from the given type | |
448 | // | |
449 | // This is needed to extract the correct attribute type from proxy classes | |
450 | // as utilized in FUSION_ADAPT_ADT et. al. | |
451 | /////////////////////////////////////////////////////////////////////////// | |
452 | template <typename Attribute, typename Enable/* = void*/> | |
453 | struct attribute_type : mpl::identity<Attribute> {}; | |
454 | ||
455 | /////////////////////////////////////////////////////////////////////////// | |
456 | // Retrieve the size of a fusion sequence (compile time) | |
457 | /////////////////////////////////////////////////////////////////////////// | |
458 | template <typename T> | |
459 | struct sequence_size | |
460 | : fusion::result_of::size<T> | |
461 | {}; | |
462 | ||
463 | template <> | |
464 | struct sequence_size<unused_type> | |
465 | : mpl::int_<0> | |
466 | {}; | |
467 | ||
468 | /////////////////////////////////////////////////////////////////////////// | |
469 | // Retrieve the size of an attribute (runtime) | |
470 | /////////////////////////////////////////////////////////////////////////// | |
471 | namespace detail | |
472 | { | |
473 | template <typename Attribute, typename Enable = void> | |
474 | struct attribute_size_impl | |
475 | { | |
476 | typedef std::size_t type; | |
477 | ||
478 | static type call(Attribute const&) | |
479 | { | |
480 | return 1; | |
481 | } | |
482 | }; | |
483 | ||
484 | template <typename Attribute> | |
485 | struct attribute_size_impl<Attribute | |
486 | , typename enable_if< | |
487 | mpl::and_< | |
488 | fusion::traits::is_sequence<Attribute> | |
489 | , mpl::not_<traits::is_container<Attribute> > | |
490 | > | |
491 | >::type> | |
492 | { | |
493 | typedef typename fusion::result_of::size<Attribute>::value_type type; | |
494 | ||
495 | static type call(Attribute const& attr) | |
496 | { | |
497 | return fusion::size(attr); | |
498 | } | |
499 | }; | |
500 | ||
501 | template <typename Attribute> | |
502 | struct attribute_size_impl<Attribute | |
503 | , typename enable_if< | |
504 | mpl::and_< | |
505 | traits::is_container<Attribute> | |
506 | , mpl::not_<traits::is_iterator_range<Attribute> > | |
507 | > | |
508 | >::type> | |
509 | { | |
510 | typedef typename Attribute::size_type type; | |
511 | ||
512 | static type call(Attribute const& attr) | |
513 | { | |
514 | return attr.size(); | |
515 | } | |
516 | }; | |
517 | } | |
518 | ||
519 | template <typename Attribute, typename Enable/* = void*/> | |
520 | struct attribute_size | |
521 | : detail::attribute_size_impl<Attribute> | |
522 | {}; | |
523 | ||
524 | template <typename Attribute> | |
525 | struct attribute_size<optional<Attribute> > | |
526 | { | |
527 | typedef typename attribute_size<Attribute>::type type; | |
528 | ||
529 | static type call(optional<Attribute> const& val) | |
530 | { | |
531 | if (!val) | |
532 | return 0; | |
533 | return traits::size(val.get()); | |
534 | } | |
535 | }; | |
536 | ||
537 | namespace detail | |
538 | { | |
539 | struct attribute_size_visitor : static_visitor<std::size_t> | |
540 | { | |
541 | template <typename T> | |
542 | std::size_t operator()(T const& val) const | |
543 | { | |
544 | return spirit::traits::size(val); | |
545 | } | |
546 | }; | |
547 | } | |
548 | ||
549 | template <BOOST_VARIANT_ENUM_PARAMS(typename T)> | |
550 | struct attribute_size<variant<BOOST_VARIANT_ENUM_PARAMS(T)> > | |
551 | { | |
552 | typedef std::size_t type; | |
553 | ||
554 | static type call(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& val) | |
555 | { | |
556 | return apply_visitor(detail::attribute_size_visitor(), val); | |
557 | } | |
558 | }; | |
559 | ||
560 | template <typename Iterator> | |
561 | struct attribute_size<iterator_range<Iterator> > | |
562 | { | |
92f5a8d4 | 563 | typedef typename std::iterator_traits<Iterator>:: |
7c673cae FG |
564 | difference_type type; |
565 | ||
566 | static type call(iterator_range<Iterator> const& r) | |
567 | { | |
92f5a8d4 | 568 | return std::distance(r.begin(), r.end()); |
7c673cae FG |
569 | } |
570 | }; | |
571 | ||
572 | template <> | |
573 | struct attribute_size<unused_type> | |
574 | { | |
575 | typedef std::size_t type; | |
576 | ||
577 | static type call(unused_type) | |
578 | { | |
579 | return 0; | |
580 | } | |
581 | }; | |
582 | ||
583 | template <typename Attribute> | |
584 | typename attribute_size<Attribute>::type | |
585 | size (Attribute const& attr) | |
586 | { | |
587 | return attribute_size<Attribute>::call(attr); | |
588 | } | |
589 | ||
590 | /////////////////////////////////////////////////////////////////////////// | |
591 | // pass_attribute | |
592 | // | |
593 | // Determines how we pass attributes to semantic actions. This | |
594 | // may be specialized. By default, all attributes are wrapped in | |
595 | // a fusion sequence, because the attribute has to be treated as being | |
596 | // a single value in any case (even if it actually already is a fusion | |
597 | // sequence in its own). | |
598 | /////////////////////////////////////////////////////////////////////////// | |
599 | template <typename Component, typename Attribute, typename Enable/* = void*/> | |
600 | struct pass_attribute | |
601 | { | |
602 | typedef fusion::vector1<Attribute&> type; | |
603 | }; | |
604 | ||
605 | /////////////////////////////////////////////////////////////////////////// | |
606 | // Subclass a pass_attribute specialization from this to wrap | |
607 | // the attribute in a tuple only IFF it is not already a fusion tuple. | |
608 | /////////////////////////////////////////////////////////////////////////// | |
609 | template <typename Attribute, typename Force = mpl::false_> | |
610 | struct wrap_if_not_tuple | |
611 | : mpl::if_< | |
612 | fusion::traits::is_sequence<Attribute> | |
613 | , Attribute&, fusion::vector1<Attribute&> > | |
614 | {}; | |
615 | ||
616 | template <typename Attribute> | |
617 | struct wrap_if_not_tuple<Attribute, mpl::true_> | |
618 | { | |
619 | typedef fusion::vector1<Attribute&> type; | |
620 | }; | |
621 | ||
622 | template <> | |
623 | struct wrap_if_not_tuple<unused_type, mpl::false_> | |
624 | { | |
625 | typedef unused_type type; | |
626 | }; | |
627 | ||
628 | template <> | |
629 | struct wrap_if_not_tuple<unused_type const, mpl::false_> | |
630 | { | |
631 | typedef unused_type type; | |
632 | }; | |
633 | ||
634 | /////////////////////////////////////////////////////////////////////////// | |
635 | // build_optional | |
636 | // | |
637 | // Build a boost::optional from T. Return unused_type if T is unused_type. | |
638 | /////////////////////////////////////////////////////////////////////////// | |
639 | template <typename T> | |
640 | struct build_optional | |
641 | { | |
642 | typedef boost::optional<T> type; | |
643 | }; | |
644 | ||
645 | template <typename T> | |
646 | struct build_optional<boost::optional<T> > | |
647 | { | |
648 | typedef boost::optional<T> type; | |
649 | }; | |
650 | ||
651 | template <> | |
652 | struct build_optional<unused_type> | |
653 | { | |
654 | typedef unused_type type; | |
655 | }; | |
656 | ||
657 | /////////////////////////////////////////////////////////////////////////// | |
658 | // build_std_vector | |
659 | // | |
660 | // Build a std::vector from T. Return unused_type if T is unused_type. | |
661 | /////////////////////////////////////////////////////////////////////////// | |
662 | template <typename T> | |
663 | struct build_std_vector | |
664 | { | |
665 | typedef std::vector<T> type; | |
666 | }; | |
667 | ||
668 | template <> | |
669 | struct build_std_vector<unused_type> | |
670 | { | |
671 | typedef unused_type type; | |
672 | }; | |
673 | ||
674 | /////////////////////////////////////////////////////////////////////////// | |
675 | // filter_unused_attributes | |
676 | // | |
677 | // Remove unused_types from a sequence | |
678 | /////////////////////////////////////////////////////////////////////////// | |
679 | ||
680 | // Compute the list of all *used* attributes of sub-components | |
681 | // (filter all unused attributes from the list) | |
682 | template <typename Sequence> | |
683 | struct filter_unused_attributes | |
684 | : fusion::result_of::filter_if<Sequence, not_is_unused<mpl::_> > | |
685 | {}; | |
686 | ||
687 | /////////////////////////////////////////////////////////////////////////// | |
688 | // sequence_attribute_transform | |
689 | // | |
690 | // This transform is invoked for every attribute in a sequence allowing | |
691 | // to modify the attribute type exposed by a component to the enclosing | |
692 | // sequence component. By default no transformation is performed. | |
693 | /////////////////////////////////////////////////////////////////////////// | |
694 | template <typename Attribute, typename Domain> | |
695 | struct sequence_attribute_transform | |
696 | : mpl::identity<Attribute> | |
697 | {}; | |
698 | ||
699 | /////////////////////////////////////////////////////////////////////////// | |
700 | // permutation_attribute_transform | |
701 | // | |
702 | // This transform is invoked for every attribute in a sequence allowing | |
703 | // to modify the attribute type exposed by a component to the enclosing | |
704 | // permutation component. By default a build_optional transformation is | |
705 | // performed. | |
706 | /////////////////////////////////////////////////////////////////////////// | |
707 | template <typename Attribute, typename Domain> | |
708 | struct permutation_attribute_transform | |
709 | : traits::build_optional<Attribute> | |
710 | {}; | |
711 | ||
712 | /////////////////////////////////////////////////////////////////////////// | |
713 | // sequential_or_attribute_transform | |
714 | // | |
715 | // This transform is invoked for every attribute in a sequential_or allowing | |
716 | // to modify the attribute type exposed by a component to the enclosing | |
717 | // sequential_or component. By default a build_optional transformation is | |
718 | // performed. | |
719 | /////////////////////////////////////////////////////////////////////////// | |
720 | template <typename Attribute, typename Domain> | |
721 | struct sequential_or_attribute_transform | |
722 | : traits::build_optional<Attribute> | |
723 | {}; | |
724 | ||
725 | /////////////////////////////////////////////////////////////////////////// | |
726 | // build_fusion_vector | |
727 | // | |
728 | // Build a fusion vector from a fusion sequence. All unused attributes | |
729 | // are filtered out. If the result is empty after the removal of unused | |
730 | // types, return unused_type. If the input sequence is an unused_type, | |
731 | // also return unused_type. | |
732 | /////////////////////////////////////////////////////////////////////////// | |
733 | template <typename Sequence> | |
734 | struct build_fusion_vector | |
735 | { | |
736 | // Remove all unused attributes | |
737 | typedef typename | |
738 | filter_unused_attributes<Sequence>::type | |
739 | filtered_attributes; | |
740 | ||
741 | // Build a fusion vector from a fusion sequence (Sequence), | |
742 | // But *only if* the sequence is not empty. i.e. if the | |
743 | // sequence is empty, our result will be unused_type. | |
744 | ||
745 | typedef typename | |
746 | mpl::eval_if< | |
747 | fusion::result_of::empty<filtered_attributes> | |
748 | , mpl::identity<unused_type> | |
749 | , fusion::result_of::as_vector<filtered_attributes> | |
750 | >::type | |
751 | type; | |
752 | }; | |
753 | ||
754 | template <> | |
755 | struct build_fusion_vector<unused_type> | |
756 | { | |
757 | typedef unused_type type; | |
758 | }; | |
759 | ||
760 | /////////////////////////////////////////////////////////////////////////// | |
761 | // build_attribute_sequence | |
762 | // | |
763 | // Build a fusion sequence attribute sequence from a sequence of | |
764 | // components. Transform<T>::type is called on each element. | |
765 | /////////////////////////////////////////////////////////////////////////// | |
766 | template <typename Sequence, typename Context | |
767 | , template <typename T, typename D> class Transform | |
768 | , typename Iterator = unused_type, typename Domain = unused_type> | |
769 | struct build_attribute_sequence | |
770 | { | |
771 | struct element_attribute | |
772 | { | |
773 | template <typename T> | |
774 | struct result; | |
775 | ||
776 | template <typename F, typename Element> | |
777 | struct result<F(Element)> | |
778 | { | |
779 | typedef typename | |
780 | Transform< | |
781 | typename attribute_of<Element, Context, Iterator>::type | |
782 | , Domain | |
783 | >::type | |
784 | type; | |
785 | }; | |
786 | ||
787 | // never called, but needed for decltype-based result_of (C++0x) | |
788 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES | |
789 | template <typename Element> | |
790 | typename result<element_attribute(Element)>::type | |
791 | operator()(Element&&) const; | |
792 | #endif | |
793 | }; | |
794 | ||
795 | // Compute the list of attributes of all sub-components | |
796 | typedef typename | |
797 | fusion::result_of::transform<Sequence, element_attribute>::type | |
798 | type; | |
799 | }; | |
800 | ||
801 | /////////////////////////////////////////////////////////////////////////// | |
802 | // has_no_unused | |
803 | // | |
804 | // Test if there are no unused attributes in Sequence | |
805 | /////////////////////////////////////////////////////////////////////////// | |
806 | template <typename Sequence> | |
807 | struct has_no_unused | |
808 | : is_same< | |
809 | typename mpl::find_if<Sequence, is_same<mpl::_, unused_type> >::type | |
810 | , typename mpl::end<Sequence>::type> | |
811 | {}; | |
812 | ||
813 | namespace detail | |
814 | { | |
815 | template <typename Sequence, bool no_unused | |
816 | , int size = mpl::size<Sequence>::value> | |
817 | struct build_collapsed_variant; | |
818 | ||
819 | // N element case, no unused | |
820 | template <typename Sequence, int size> | |
821 | struct build_collapsed_variant<Sequence, true, size> | |
822 | : spirit::detail::as_variant<Sequence> {}; | |
823 | ||
824 | // N element case with unused | |
825 | template <typename Sequence, int size> | |
826 | struct build_collapsed_variant<Sequence, false, size> | |
827 | { | |
828 | typedef boost::optional< | |
829 | typename spirit::detail::as_variant< | |
830 | typename fusion::result_of::pop_front<Sequence>::type | |
831 | >::type | |
832 | > type; | |
833 | }; | |
834 | ||
835 | // 1 element case, no unused | |
836 | template <typename Sequence> | |
837 | struct build_collapsed_variant<Sequence, true, 1> | |
838 | : mpl::front<Sequence> {}; | |
839 | ||
840 | // 1 element case, with unused | |
841 | template <typename Sequence> | |
842 | struct build_collapsed_variant<Sequence, false, 1> | |
843 | : mpl::front<Sequence> {}; | |
844 | ||
845 | // 2 element case, no unused | |
846 | template <typename Sequence> | |
847 | struct build_collapsed_variant<Sequence, true, 2> | |
848 | : spirit::detail::as_variant<Sequence> {}; | |
849 | ||
850 | // 2 element case, with unused | |
851 | template <typename Sequence> | |
852 | struct build_collapsed_variant<Sequence, false, 2> | |
853 | { | |
854 | typedef boost::optional< | |
855 | typename mpl::deref< | |
856 | typename mpl::next< | |
857 | typename mpl::begin<Sequence>::type | |
858 | >::type | |
859 | >::type | |
860 | > | |
861 | type; | |
862 | }; | |
863 | } | |
864 | ||
865 | /////////////////////////////////////////////////////////////////////////// | |
866 | // alternative_attribute_transform | |
867 | // | |
868 | // This transform is invoked for every attribute in an alternative allowing | |
869 | // to modify the attribute type exposed by a component to the enclosing | |
870 | // alternative component. By default no transformation is performed. | |
871 | /////////////////////////////////////////////////////////////////////////// | |
872 | template <typename Attribute, typename Domain> | |
873 | struct alternative_attribute_transform | |
874 | : mpl::identity<Attribute> | |
875 | {}; | |
876 | ||
877 | /////////////////////////////////////////////////////////////////////////// | |
878 | // build_variant | |
879 | // | |
880 | // Build a boost::variant from a fusion sequence. build_variant makes sure | |
881 | // that 1) all attributes in the variant are unique 2) puts the unused | |
882 | // attribute, if there is any, to the front and 3) collapses single element | |
883 | // variants, variant<T> to T. | |
884 | /////////////////////////////////////////////////////////////////////////// | |
885 | template <typename Sequence> | |
886 | struct build_variant | |
887 | { | |
888 | // Remove all unused attributes. | |
889 | typedef typename | |
890 | filter_unused_attributes<Sequence>::type | |
891 | filtered_attributes; | |
892 | ||
893 | typedef has_no_unused<Sequence> no_unused; | |
894 | ||
895 | // If the original attribute list does not contain any unused | |
896 | // attributes, it is used, otherwise a single unused_type is | |
897 | // pushed to the front of the list. This is to make sure that if | |
898 | // there is an unused_type in the list, it is the first one. | |
899 | typedef typename | |
900 | mpl::eval_if< | |
901 | no_unused, | |
902 | mpl::identity<Sequence>, | |
903 | fusion::result_of::push_front<filtered_attributes, unused_type> | |
904 | >::type | |
905 | attribute_sequence; | |
906 | ||
907 | // Make sure each of the types occur only once in the type list | |
908 | typedef typename | |
909 | mpl::fold< | |
910 | attribute_sequence, mpl::vector<>, | |
911 | mpl::if_< | |
912 | mpl::contains<mpl::_1, mpl::_2>, | |
913 | mpl::_1, mpl::push_back<mpl::_1, mpl::_2> | |
914 | > | |
915 | >::type | |
916 | no_duplicates; | |
917 | ||
918 | // If there is only one type in the list of types we strip off the | |
919 | // variant. IOTW, collapse single element variants, variant<T> to T. | |
920 | // Take note that this also collapses variant<unused_type, T> to T. | |
921 | typedef typename | |
922 | traits::detail::build_collapsed_variant< | |
923 | no_duplicates, no_unused::value>::type | |
924 | type; | |
925 | }; | |
926 | ||
92f5a8d4 TL |
927 | namespace detail { |
928 | // Domain-agnostic class template partial specializations and | |
929 | // type agnostic domain partial specializations are ambious. | |
930 | // To resolve the ambiguity type agnostic domain partial | |
931 | // specializations are dispatched via intermediate type. | |
932 | template <typename Exposed, typename Transformed, typename Domain> | |
933 | struct transform_attribute_base; | |
934 | ||
935 | template <typename Attribute> | |
936 | struct synthesize_attribute | |
937 | { | |
938 | typedef Attribute type; | |
939 | static Attribute pre(unused_type) { return Attribute(); } | |
940 | static void post(unused_type, Attribute const&) {} | |
941 | static void fail(unused_type) {} | |
942 | }; | |
943 | } | |
7c673cae FG |
944 | /////////////////////////////////////////////////////////////////////////// |
945 | // transform_attribute | |
946 | // | |
947 | // Sometimes the user needs to transform the attribute types for certain | |
948 | // attributes. This template can be used as a customization point, where | |
949 | // the user is able specify specific transformation rules for any attribute | |
950 | // type. | |
92f5a8d4 TL |
951 | // |
952 | // Note: the transformations involving unused_type are internal details | |
953 | // and may be subject to change at any time. | |
954 | // | |
7c673cae FG |
955 | /////////////////////////////////////////////////////////////////////////// |
956 | template <typename Exposed, typename Transformed, typename Domain | |
957 | , typename Enable/* = void*/> | |
92f5a8d4 TL |
958 | struct transform_attribute |
959 | : detail::transform_attribute_base<Exposed, Transformed, Domain> | |
7c673cae | 960 | { |
92f5a8d4 TL |
961 | BOOST_STATIC_ASSERT_MSG(!is_reference<Exposed>::value, |
962 | "Exposed cannot be a reference type"); | |
963 | BOOST_STATIC_ASSERT_MSG(!is_reference<Transformed>::value, | |
964 | "Transformed cannot be a reference type"); | |
7c673cae FG |
965 | }; |
966 | ||
92f5a8d4 TL |
967 | template <typename Transformed, typename Domain> |
968 | struct transform_attribute<unused_type, Transformed, Domain> | |
969 | : detail::synthesize_attribute<Transformed> | |
7c673cae FG |
970 | {}; |
971 | ||
92f5a8d4 TL |
972 | template <typename Transformed, typename Domain> |
973 | struct transform_attribute<unused_type const, Transformed, Domain> | |
974 | : detail::synthesize_attribute<Transformed> | |
7c673cae FG |
975 | {}; |
976 | ||
7c673cae FG |
977 | /////////////////////////////////////////////////////////////////////////// |
978 | // swap_impl | |
979 | // | |
980 | // Swap (with proper handling of unused_types) | |
981 | /////////////////////////////////////////////////////////////////////////// | |
982 | template <typename A, typename B> | |
983 | void swap_impl(A& a, B& b) | |
984 | { | |
985 | A temp = a; | |
986 | a = b; | |
987 | b = temp; | |
988 | } | |
989 | ||
990 | template <typename T> | |
991 | void swap_impl(T& a, T& b) | |
992 | { | |
b32b8144 | 993 | boost::swap(a, b); |
7c673cae FG |
994 | } |
995 | ||
996 | template <typename A> | |
997 | void swap_impl(A&, unused_type) | |
998 | { | |
999 | } | |
1000 | ||
1001 | template <typename A> | |
1002 | void swap_impl(unused_type, A&) | |
1003 | { | |
1004 | } | |
1005 | ||
1006 | inline void swap_impl(unused_type, unused_type) | |
1007 | { | |
1008 | } | |
1009 | ||
1010 | /////////////////////////////////////////////////////////////////////////// | |
1011 | // Strips single element fusion vectors into its 'naked' | |
1012 | // form: vector<T> --> T | |
1013 | /////////////////////////////////////////////////////////////////////////// | |
1014 | template <typename T> | |
1015 | struct strip_single_element_vector | |
1016 | { | |
1017 | typedef T type; | |
1018 | }; | |
1019 | ||
1020 | #if !defined(BOOST_FUSION_HAS_VARIADIC_VECTOR) | |
1021 | template <typename T> | |
1022 | struct strip_single_element_vector<fusion::vector1<T> > | |
1023 | { | |
1024 | typedef T type; | |
1025 | }; | |
1026 | #endif | |
1027 | template <typename T> | |
1028 | struct strip_single_element_vector<fusion::vector<T> > | |
1029 | { | |
1030 | typedef T type; | |
1031 | }; | |
1032 | ||
1033 | /////////////////////////////////////////////////////////////////////////// | |
1034 | // meta function to return whether the argument is a one element fusion | |
1035 | // sequence | |
1036 | /////////////////////////////////////////////////////////////////////////// | |
1037 | template <typename T | |
1038 | , bool IsFusionSeq = fusion::traits::is_sequence<T>::value | |
1039 | , bool IsProtoExpr = proto::is_expr<T>::value> | |
1040 | struct one_element_sequence | |
1041 | : mpl::false_ | |
1042 | {}; | |
1043 | ||
1044 | template <typename T> | |
1045 | struct one_element_sequence<T, true, false> | |
1046 | : mpl::bool_<mpl::size<T>::value == 1> | |
1047 | {}; | |
1048 | ||
1049 | /////////////////////////////////////////////////////////////////////////// | |
1050 | // clear | |
1051 | // | |
1052 | // Clear data efficiently | |
1053 | /////////////////////////////////////////////////////////////////////////// | |
1054 | template <typename T> | |
1055 | void clear(T& val); | |
1056 | ||
1057 | namespace detail | |
1058 | { | |
1059 | // this is used by the variant and fusion sequence dispatch | |
1060 | struct clear_visitor : static_visitor<> | |
1061 | { | |
1062 | template <typename T> | |
1063 | void operator()(T& val) const | |
1064 | { | |
1065 | spirit::traits::clear(val); | |
1066 | } | |
1067 | }; | |
1068 | ||
1069 | // default | |
1070 | template <typename T> | |
1071 | void clear_impl2(T& val, mpl::false_) | |
1072 | { | |
1073 | val = T(); | |
1074 | } | |
1075 | ||
1076 | // for fusion sequences | |
1077 | template <typename T> | |
1078 | void clear_impl2(T& val, mpl::true_) | |
1079 | { | |
1080 | fusion::for_each(val, clear_visitor()); | |
1081 | } | |
1082 | ||
1083 | // dispatch default or fusion sequence | |
1084 | template <typename T> | |
1085 | void clear_impl(T& val, mpl::false_) | |
1086 | { | |
1087 | clear_impl2(val, fusion::traits::is_sequence<T>()); | |
1088 | } | |
1089 | ||
1090 | // STL containers | |
1091 | template <typename T> | |
1092 | void clear_impl(T& val, mpl::true_) | |
1093 | { | |
1094 | val.clear(); | |
1095 | } | |
1096 | } | |
1097 | ||
1098 | template <typename T, typename Enable/* = void*/> | |
1099 | struct clear_value | |
1100 | { | |
1101 | static void call(T& val) | |
1102 | { | |
1103 | detail::clear_impl(val, typename is_container<T>::type()); | |
1104 | } | |
1105 | }; | |
1106 | ||
1107 | // optionals | |
1108 | template <typename T> | |
1109 | struct clear_value<boost::optional<T> > | |
1110 | { | |
1111 | static void call(boost::optional<T>& val) | |
1112 | { | |
1113 | if (val) | |
1114 | val = none; // leave optional uninitialized | |
1115 | } | |
1116 | }; | |
1117 | ||
1118 | // variants | |
1119 | template <BOOST_VARIANT_ENUM_PARAMS(typename T)> | |
1120 | struct clear_value<variant<BOOST_VARIANT_ENUM_PARAMS(T)> > | |
1121 | { | |
1122 | static void call(variant<BOOST_VARIANT_ENUM_PARAMS(T)>& val) | |
1123 | { | |
1124 | apply_visitor(detail::clear_visitor(), val); | |
1125 | } | |
1126 | }; | |
1127 | ||
1128 | // iterator range | |
1129 | template <typename T> | |
1130 | struct clear_value<iterator_range<T> > | |
1131 | { | |
1132 | static void call(iterator_range<T>& val) | |
1133 | { | |
1134 | val = iterator_range<T>(val.end(), val.end()); | |
1135 | } | |
1136 | }; | |
1137 | ||
1138 | // main dispatch | |
1139 | template <typename T> | |
1140 | void clear(T& val) | |
1141 | { | |
1142 | clear_value<T>::call(val); | |
1143 | } | |
1144 | ||
1145 | // for unused | |
1146 | inline void clear(unused_type) | |
1147 | { | |
1148 | } | |
1149 | ||
1150 | /////////////////////////////////////////////////////////////////////////// | |
1151 | namespace detail | |
1152 | { | |
1153 | template <typename Out> | |
1154 | struct print_fusion_sequence | |
1155 | { | |
1156 | print_fusion_sequence(Out& out_) | |
1157 | : out(out_), is_first(true) {} | |
1158 | ||
1159 | typedef void result_type; | |
1160 | ||
1161 | template <typename T> | |
1162 | void operator()(T const& val) const | |
1163 | { | |
1164 | if (is_first) | |
1165 | is_first = false; | |
1166 | else | |
1167 | out << ", "; | |
1168 | spirit::traits::print_attribute(out, val); | |
1169 | } | |
1170 | ||
1171 | Out& out; | |
1172 | mutable bool is_first; | |
1173 | }; | |
1174 | ||
1175 | // print elements in a variant | |
1176 | template <typename Out> | |
1177 | struct print_visitor : static_visitor<> | |
1178 | { | |
1179 | print_visitor(Out& out_) : out(out_) {} | |
1180 | ||
1181 | template <typename T> | |
1182 | void operator()(T const& val) const | |
1183 | { | |
1184 | spirit::traits::print_attribute(out, val); | |
1185 | } | |
1186 | ||
1187 | Out& out; | |
1188 | }; | |
1189 | } | |
1190 | ||
1191 | template <typename Out, typename T, typename Enable> | |
1192 | struct print_attribute_debug | |
1193 | { | |
1194 | // for plain data types | |
1195 | template <typename T_> | |
1196 | static void call_impl3(Out& out, T_ const& val, mpl::false_) | |
1197 | { | |
1198 | out << val; | |
1199 | } | |
1200 | ||
1201 | // for fusion data types | |
1202 | template <typename T_> | |
1203 | static void call_impl3(Out& out, T_ const& val, mpl::true_) | |
1204 | { | |
1205 | out << '['; | |
1206 | fusion::for_each(val, detail::print_fusion_sequence<Out>(out)); | |
1207 | out << ']'; | |
1208 | } | |
1209 | ||
1210 | // non-stl container | |
1211 | template <typename T_> | |
1212 | static void call_impl2(Out& out, T_ const& val, mpl::false_) | |
1213 | { | |
1214 | call_impl3(out, val, fusion::traits::is_sequence<T_>()); | |
1215 | } | |
1216 | ||
1217 | // stl container | |
1218 | template <typename T_> | |
1219 | static void call_impl2(Out& out, T_ const& val, mpl::true_) | |
1220 | { | |
1221 | out << '['; | |
1222 | if (!traits::is_empty(val)) | |
1223 | { | |
1224 | bool first = true; | |
1225 | typename container_iterator<T_ const>::type iend = traits::end(val); | |
1226 | for (typename container_iterator<T_ const>::type i = traits::begin(val); | |
1227 | !traits::compare(i, iend); traits::next(i)) | |
1228 | { | |
1229 | if (!first) | |
1230 | out << ", "; | |
1231 | first = false; | |
1232 | spirit::traits::print_attribute(out, traits::deref(i)); | |
1233 | } | |
1234 | } | |
1235 | out << ']'; | |
1236 | } | |
1237 | ||
1238 | // for variant types | |
1239 | template <typename T_> | |
1240 | static void call_impl(Out& out, T_ const& val, mpl::false_) | |
1241 | { | |
1242 | apply_visitor(detail::print_visitor<Out>(out), val); | |
1243 | } | |
1244 | ||
1245 | // for non-variant types | |
1246 | template <typename T_> | |
1247 | static void call_impl(Out& out, T_ const& val, mpl::true_) | |
1248 | { | |
1249 | call_impl2(out, val, is_container<T_>()); | |
1250 | } | |
1251 | ||
1252 | // main entry point | |
1253 | static void call(Out& out, T const& val) | |
1254 | { | |
1255 | call_impl(out, val, not_is_variant<T>()); | |
1256 | } | |
1257 | }; | |
1258 | ||
1259 | template <typename Out, typename T> | |
1260 | struct print_attribute_debug<Out, boost::optional<T> > | |
1261 | { | |
1262 | static void call(Out& out, boost::optional<T> const& val) | |
1263 | { | |
1264 | if (val) | |
1265 | spirit::traits::print_attribute(out, *val); | |
1266 | else | |
1267 | out << "[empty]"; | |
1268 | } | |
1269 | }; | |
1270 | ||
1271 | /////////////////////////////////////////////////////////////////////////// | |
1272 | template <typename Out, typename T> | |
1273 | inline void print_attribute(Out& out, T const& val) | |
1274 | { | |
1275 | print_attribute_debug<Out, T>::call(out, val); | |
1276 | } | |
1277 | ||
1278 | template <typename Out> | |
1279 | inline void print_attribute(Out&, unused_type) | |
1280 | { | |
1281 | } | |
1282 | ||
1283 | /////////////////////////////////////////////////////////////////////////// | |
1284 | // generate debug output for lookahead token (character) stream | |
1285 | namespace detail | |
1286 | { | |
1287 | struct token_printer_debug_for_chars | |
1288 | { | |
1289 | template<typename Out, typename Char> | |
1290 | static void print(Out& o, Char c) | |
1291 | { | |
1292 | using namespace std; // allow for ADL to find the proper iscntrl | |
1293 | ||
1294 | if (c == static_cast<Char>('\a')) | |
1295 | o << "\\a"; | |
1296 | else if (c == static_cast<Char>('\b')) | |
1297 | o << "\\b"; | |
1298 | else if (c == static_cast<Char>('\f')) | |
1299 | o << "\\f"; | |
1300 | else if (c == static_cast<Char>('\n')) | |
1301 | o << "\\n"; | |
1302 | else if (c == static_cast<Char>('\r')) | |
1303 | o << "\\r"; | |
1304 | else if (c == static_cast<Char>('\t')) | |
1305 | o << "\\t"; | |
1306 | else if (c == static_cast<Char>('\v')) | |
1307 | o << "\\v"; | |
1308 | else if (c >= 0 && c < 127 && iscntrl(c)) | |
1309 | o << "\\" << std::oct << static_cast<int>(c); | |
1310 | else | |
1311 | o << static_cast<char>(c); | |
1312 | } | |
1313 | }; | |
1314 | ||
1315 | // for token types where the comparison with char constants wouldn't work | |
1316 | struct token_printer_debug | |
1317 | { | |
1318 | template<typename Out, typename T> | |
1319 | static void print(Out& o, T const& val) | |
1320 | { | |
1321 | o << val; | |
1322 | } | |
1323 | }; | |
1324 | } | |
1325 | ||
1326 | template <typename T, typename Enable> | |
1327 | struct token_printer_debug | |
1328 | : mpl::if_< | |
1329 | mpl::and_< | |
1330 | is_convertible<T, char>, is_convertible<char, T> > | |
1331 | , detail::token_printer_debug_for_chars | |
1332 | , detail::token_printer_debug>::type | |
1333 | {}; | |
1334 | ||
1335 | template <typename Out, typename T> | |
1336 | inline void print_token(Out& out, T const& val) | |
1337 | { | |
1338 | // allow to customize the token printer routine | |
1339 | token_printer_debug<T>::print(out, val); | |
1340 | } | |
1341 | }}} | |
1342 | ||
7c673cae | 1343 | #endif |