]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Copyright (c) 2001-2011 Joel de Guzman | |
3 | Copyright (c) 2001-2011 Hartmut Kaiser | |
4 | http://spirit.sourceforge.net/ | |
5 | ||
6 | Distributed under the Boost Software License, Version 1.0. (See accompanying | |
7 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
8 | =============================================================================*/ | |
9 | #if !defined(BOOST_SPIRIT_CONTAINER_FEBRUARY_06_2007_1001AM) | |
10 | #define BOOST_SPIRIT_CONTAINER_FEBRUARY_06_2007_1001AM | |
11 | ||
12 | #if defined(_MSC_VER) | |
13 | #pragma once | |
14 | #endif | |
15 | ||
16 | #include <boost/spirit/home/support/unused.hpp> | |
17 | #include <boost/spirit/home/support/attributes_fwd.hpp> | |
18 | #include <boost/detail/iterator.hpp> // for boost::detail::iterator_traits | |
19 | #include <boost/mpl/has_xxx.hpp> | |
20 | #include <boost/mpl/bool.hpp> | |
21 | #include <boost/optional.hpp> | |
22 | #include <boost/variant.hpp> | |
23 | #include <boost/preprocessor/cat.hpp> | |
24 | #include <boost/preprocessor/repeat.hpp> | |
25 | #include <boost/range/iterator_range.hpp> | |
26 | ||
27 | namespace boost { namespace spirit { namespace traits | |
28 | { | |
29 | /////////////////////////////////////////////////////////////////////////// | |
30 | // This file contains some container utils for stl containers. The | |
31 | // utilities provided also accept spirit's unused_type; all no-ops. | |
32 | // Compiler optimization will easily strip these away. | |
33 | /////////////////////////////////////////////////////////////////////////// | |
34 | ||
35 | namespace detail | |
36 | { | |
37 | BOOST_MPL_HAS_XXX_TRAIT_DEF(value_type) | |
38 | BOOST_MPL_HAS_XXX_TRAIT_DEF(iterator) | |
39 | BOOST_MPL_HAS_XXX_TRAIT_DEF(size_type) | |
40 | BOOST_MPL_HAS_XXX_TRAIT_DEF(reference) | |
41 | } | |
42 | ||
43 | template <typename T, typename Enable/* = void*/> | |
44 | struct is_container | |
45 | : mpl::bool_< | |
46 | detail::has_value_type<T>::value && | |
47 | detail::has_iterator<T>::value && | |
48 | detail::has_size_type<T>::value && | |
49 | detail::has_reference<T>::value> | |
50 | {}; | |
51 | ||
52 | template <typename T> | |
53 | struct is_container<T&> | |
54 | : is_container<T> | |
55 | {}; | |
56 | ||
57 | template <typename T> | |
58 | struct is_container<boost::optional<T> > | |
59 | : is_container<T> | |
60 | {}; | |
61 | ||
62 | #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) | |
63 | template<typename T> | |
64 | struct is_container<boost::variant<T> > | |
65 | : is_container<T> | |
66 | {}; | |
67 | ||
68 | template<typename T0, typename T1, typename ...TN> | |
69 | struct is_container<boost::variant<T0, T1, TN...> > | |
70 | : mpl::bool_<is_container<T0>::value || | |
71 | is_container<boost::variant<T1, TN...> >::value> | |
72 | {}; | |
73 | ||
74 | #else | |
75 | #define BOOST_SPIRIT_IS_CONTAINER(z, N, data) \ | |
76 | is_container<BOOST_PP_CAT(T, N)>::value || \ | |
77 | /***/ | |
78 | ||
79 | // make sure unused variant parameters do not affect the outcome | |
80 | template <> | |
81 | struct is_container<boost::detail::variant::void_> | |
82 | : mpl::false_ | |
83 | {}; | |
84 | ||
85 | template <BOOST_VARIANT_ENUM_PARAMS(typename T)> | |
86 | struct is_container<variant<BOOST_VARIANT_ENUM_PARAMS(T)> > | |
87 | : mpl::bool_<BOOST_PP_REPEAT(BOOST_VARIANT_LIMIT_TYPES | |
88 | , BOOST_SPIRIT_IS_CONTAINER, _) false> | |
89 | {}; | |
90 | ||
91 | #undef BOOST_SPIRIT_IS_CONTAINER | |
92 | #endif | |
93 | ||
94 | template <typename T, typename Enable/* = void*/> | |
95 | struct is_iterator_range | |
96 | : mpl::false_ | |
97 | {}; | |
98 | ||
99 | template <typename T> | |
100 | struct is_iterator_range<iterator_range<T> > | |
101 | : mpl::true_ | |
102 | {}; | |
103 | ||
104 | /////////////////////////////////////////////////////////////////////////// | |
105 | namespace detail | |
106 | { | |
107 | template <typename T> | |
108 | struct remove_value_const | |
109 | { | |
110 | typedef T type; | |
111 | }; | |
112 | ||
113 | template <typename T> | |
114 | struct remove_value_const<T const> | |
115 | : remove_value_const<T> | |
116 | {}; | |
117 | ||
118 | template <typename F, typename S> | |
119 | struct remove_value_const<std::pair<F, S> > | |
120 | { | |
121 | typedef typename remove_value_const<F>::type first_type; | |
122 | typedef typename remove_value_const<S>::type second_type; | |
123 | typedef std::pair<first_type, second_type> type; | |
124 | }; | |
125 | } | |
126 | ||
127 | /////////////////////////////////////////////////////////////////////// | |
128 | //[customization_container_value_default | |
129 | template <typename Container, typename Enable/* = void*/> | |
130 | struct container_value | |
131 | : detail::remove_value_const<typename Container::value_type> | |
132 | {}; | |
133 | //] | |
134 | ||
135 | template <typename T> | |
136 | struct container_value<T&> | |
137 | : container_value<T> | |
138 | {}; | |
139 | ||
140 | // this will be instantiated if the optional holds a container | |
141 | template <typename T> | |
142 | struct container_value<boost::optional<T> > | |
143 | : container_value<T> | |
144 | {}; | |
145 | ||
146 | // this will be instantiated if the variant holds a container | |
147 | template <BOOST_VARIANT_ENUM_PARAMS(typename T)> | |
148 | struct container_value<variant<BOOST_VARIANT_ENUM_PARAMS(T)> > | |
149 | { | |
150 | typedef typename | |
151 | variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types | |
152 | types; | |
153 | typedef typename | |
154 | mpl::find_if<types, is_container<mpl::_1> >::type | |
155 | iter; | |
156 | ||
157 | typedef typename container_value< | |
158 | typename mpl::if_< | |
159 | is_same<iter, typename mpl::end<types>::type> | |
160 | , unused_type, typename mpl::deref<iter>::type | |
161 | >::type | |
162 | >::type type; | |
163 | }; | |
164 | ||
165 | //[customization_container_value_unused | |
166 | template <> | |
167 | struct container_value<unused_type> | |
168 | { | |
169 | typedef unused_type type; | |
170 | }; | |
171 | //] | |
172 | ||
173 | template <> | |
174 | struct container_value<unused_type const> | |
175 | { | |
176 | typedef unused_type type; | |
177 | }; | |
178 | ||
179 | /////////////////////////////////////////////////////////////////////////// | |
180 | template <typename Container, typename Enable/* = void*/> | |
181 | struct container_iterator | |
182 | { | |
183 | typedef typename Container::iterator type; | |
184 | }; | |
185 | ||
186 | template <typename Container> | |
187 | struct container_iterator<Container&> | |
188 | : container_iterator<Container> | |
189 | {}; | |
190 | ||
191 | template <typename Container> | |
192 | struct container_iterator<Container const> | |
193 | { | |
194 | typedef typename Container::const_iterator type; | |
195 | }; | |
196 | ||
197 | template <typename T> | |
198 | struct container_iterator<optional<T> > | |
199 | : container_iterator<T> | |
200 | {}; | |
201 | ||
202 | template <typename T> | |
203 | struct container_iterator<optional<T> const> | |
204 | : container_iterator<T const> | |
205 | {}; | |
206 | ||
207 | template <typename Iterator> | |
208 | struct container_iterator<iterator_range<Iterator> > | |
209 | { | |
210 | typedef typename range_const_iterator< | |
211 | iterator_range<Iterator> >::type type; | |
212 | }; | |
213 | ||
214 | template <> | |
215 | struct container_iterator<unused_type> | |
216 | { | |
217 | typedef unused_type const* type; | |
218 | }; | |
219 | ||
220 | template <> | |
221 | struct container_iterator<unused_type const> | |
222 | { | |
223 | typedef unused_type const* type; | |
224 | }; | |
225 | ||
226 | /////////////////////////////////////////////////////////////////////////// | |
227 | template <typename T, typename Enable/* = void*/> | |
228 | struct optional_attribute | |
229 | { | |
230 | typedef T const& type; | |
231 | ||
232 | static type call(T const& val) | |
233 | { | |
234 | return val; | |
235 | } | |
236 | ||
237 | static bool is_valid(T const&) | |
238 | { | |
239 | return true; | |
240 | } | |
241 | }; | |
242 | ||
243 | template <typename T> | |
244 | struct optional_attribute<boost::optional<T> > | |
245 | { | |
246 | typedef T const& type; | |
247 | ||
248 | static type call(boost::optional<T> const& val) | |
249 | { | |
250 | return boost::get<T>(val); | |
251 | } | |
252 | ||
253 | static bool is_valid(boost::optional<T> const& val) | |
254 | { | |
255 | return !!val; | |
256 | } | |
257 | }; | |
258 | ||
259 | template <typename T> | |
260 | typename optional_attribute<T>::type | |
261 | optional_value(T const& val) | |
262 | { | |
263 | return optional_attribute<T>::call(val); | |
264 | } | |
265 | ||
266 | inline unused_type optional_value(unused_type) | |
267 | { | |
268 | return unused; | |
269 | } | |
270 | ||
271 | template <typename T> | |
272 | bool has_optional_value(T const& val) | |
273 | { | |
274 | return optional_attribute<T>::is_valid(val); | |
275 | } | |
276 | ||
277 | inline bool has_optional_value(unused_type) | |
278 | { | |
279 | return true; | |
280 | } | |
281 | ||
282 | /////////////////////////////////////////////////////////////////////////// | |
283 | template <typename Container, typename T> | |
284 | bool push_back(Container& c, T const& val); | |
285 | ||
286 | //[customization_push_back_default | |
287 | template <typename Container, typename T, typename Enable/* = void*/> | |
288 | struct push_back_container | |
289 | { | |
290 | static bool call(Container& c, T const& val) | |
291 | { | |
292 | c.insert(c.end(), val); | |
293 | return true; | |
294 | } | |
295 | }; | |
296 | //] | |
297 | ||
298 | template <typename Container, typename T> | |
299 | struct push_back_container<optional<Container>, T> | |
300 | { | |
301 | static bool call(boost::optional<Container>& c, T const& val) | |
302 | { | |
303 | if (!c) | |
304 | c = Container(); | |
305 | return push_back(boost::get<Container>(c), val); | |
306 | } | |
307 | }; | |
308 | ||
309 | namespace detail | |
310 | { | |
311 | template <typename T> | |
312 | struct push_back_visitor : public static_visitor<> | |
313 | { | |
314 | typedef bool result_type; | |
315 | ||
316 | push_back_visitor(T const& t) : t_(t) {} | |
317 | ||
318 | template <typename Container> | |
319 | bool push_back_impl(Container& c, mpl::true_) const | |
320 | { | |
321 | return push_back(c, t_); | |
322 | } | |
323 | ||
324 | template <typename T_> | |
325 | bool push_back_impl(T_&, mpl::false_) const | |
326 | { | |
327 | // this variant doesn't hold a container | |
328 | BOOST_ASSERT(false && "This variant doesn't hold a container"); | |
329 | return false; | |
330 | } | |
331 | ||
332 | template <typename T_> | |
333 | bool operator()(T_& c) const | |
334 | { | |
335 | return push_back_impl(c, typename is_container<T_>::type()); | |
336 | } | |
337 | ||
338 | T const& t_; | |
339 | }; | |
340 | } | |
341 | ||
342 | template <BOOST_VARIANT_ENUM_PARAMS(typename T_), typename T> | |
343 | struct push_back_container<variant<BOOST_VARIANT_ENUM_PARAMS(T_)>, T> | |
344 | { | |
345 | static bool call(variant<BOOST_VARIANT_ENUM_PARAMS(T_)>& c, T const& val) | |
346 | { | |
347 | return apply_visitor(detail::push_back_visitor<T>(val), c); | |
348 | } | |
349 | }; | |
350 | ||
351 | template <typename Container, typename T> | |
352 | bool push_back(Container& c, T const& val) | |
353 | { | |
354 | return push_back_container<Container, T>::call(c, val); | |
355 | } | |
356 | ||
357 | //[customization_push_back_unused | |
358 | template <typename Container> | |
359 | bool push_back(Container&, unused_type) | |
360 | { | |
361 | return true; | |
362 | } | |
363 | //] | |
364 | ||
365 | template <typename T> | |
366 | bool push_back(unused_type, T const&) | |
367 | { | |
368 | return true; | |
369 | } | |
370 | ||
371 | inline bool push_back(unused_type, unused_type) | |
372 | { | |
373 | return true; | |
374 | } | |
375 | ||
376 | /////////////////////////////////////////////////////////////////////////// | |
377 | template <typename Container, typename Enable/* = void*/> | |
378 | struct is_empty_container | |
379 | { | |
380 | static bool call(Container const& c) | |
381 | { | |
382 | return c.empty(); | |
383 | } | |
384 | }; | |
385 | ||
386 | template <typename Container> | |
387 | bool is_empty(Container const& c) | |
388 | { | |
389 | return is_empty_container<Container>::call(c); | |
390 | } | |
391 | ||
392 | inline bool is_empty(unused_type) | |
393 | { | |
394 | return true; | |
395 | } | |
396 | ||
397 | /////////////////////////////////////////////////////////////////////////// | |
398 | // Ensure the attribute is actually a container type | |
399 | template <typename Container, typename Enable/* = void*/> | |
400 | struct make_container_attribute | |
401 | { | |
402 | static void call(Container&) | |
403 | { | |
404 | // for static types this function does nothing | |
405 | } | |
406 | }; | |
407 | ||
408 | template <typename T> | |
409 | void make_container(T& t) | |
410 | { | |
411 | make_container_attribute<T>::call(t); | |
412 | } | |
413 | ||
414 | inline void make_container(unused_type) | |
415 | { | |
416 | } | |
417 | ||
418 | /////////////////////////////////////////////////////////////////////////// | |
419 | template <typename Container, typename Enable/* = void*/> | |
420 | struct begin_container | |
421 | { | |
422 | static typename container_iterator<Container>::type call(Container& c) | |
423 | { | |
424 | return c.begin(); | |
425 | } | |
426 | }; | |
427 | ||
428 | template <typename Container> | |
429 | typename spirit::result_of::begin<Container>::type | |
430 | begin(Container& c) | |
431 | { | |
432 | return begin_container<Container>::call(c); | |
433 | } | |
434 | ||
435 | inline unused_type const* | |
436 | begin(unused_type) | |
437 | { | |
438 | return &unused; | |
439 | } | |
440 | ||
441 | /////////////////////////////////////////////////////////////////////////// | |
442 | template <typename Container, typename Enable/* = void*/> | |
443 | struct end_container | |
444 | { | |
445 | static typename container_iterator<Container>::type call(Container& c) | |
446 | { | |
447 | return c.end(); | |
448 | } | |
449 | }; | |
450 | ||
451 | template <typename Container> | |
452 | inline typename spirit::result_of::end<Container>::type | |
453 | end(Container& c) | |
454 | { | |
455 | return end_container<Container>::call(c); | |
456 | } | |
457 | ||
458 | inline unused_type const* | |
459 | end(unused_type) | |
460 | { | |
461 | return &unused; | |
462 | } | |
463 | ||
464 | /////////////////////////////////////////////////////////////////////////// | |
465 | template <typename Iterator, typename Enable/* = void*/> | |
466 | struct deref_iterator | |
467 | { | |
468 | typedef typename boost::detail::iterator_traits<Iterator>::reference type; | |
469 | static type call(Iterator& it) | |
470 | { | |
471 | return *it; | |
472 | } | |
473 | }; | |
474 | ||
475 | template <typename Iterator> | |
476 | typename deref_iterator<Iterator>::type | |
477 | deref(Iterator& it) | |
478 | { | |
479 | return deref_iterator<Iterator>::call(it); | |
480 | } | |
481 | ||
482 | inline unused_type | |
483 | deref(unused_type const*) | |
484 | { | |
485 | return unused; | |
486 | } | |
487 | ||
488 | /////////////////////////////////////////////////////////////////////////// | |
489 | template <typename Iterator, typename Enable/* = void*/> | |
490 | struct next_iterator | |
491 | { | |
492 | static void call(Iterator& it) | |
493 | { | |
494 | ++it; | |
495 | } | |
496 | }; | |
497 | ||
498 | template <typename Iterator> | |
499 | void next(Iterator& it) | |
500 | { | |
501 | next_iterator<Iterator>::call(it); | |
502 | } | |
503 | ||
504 | inline void next(unused_type const*) | |
505 | { | |
506 | // do nothing | |
507 | } | |
508 | ||
509 | /////////////////////////////////////////////////////////////////////////// | |
510 | template <typename Iterator, typename Enable/* = void*/> | |
511 | struct compare_iterators | |
512 | { | |
513 | static bool call(Iterator const& it1, Iterator const& it2) | |
514 | { | |
515 | return it1 == it2; | |
516 | } | |
517 | }; | |
518 | ||
519 | template <typename Iterator> | |
520 | bool compare(Iterator& it1, Iterator& it2) | |
521 | { | |
522 | return compare_iterators<Iterator>::call(it1, it2); | |
523 | } | |
524 | ||
525 | inline bool compare(unused_type const*, unused_type const*) | |
526 | { | |
527 | return false; | |
528 | } | |
529 | }}} | |
530 | ||
531 | /////////////////////////////////////////////////////////////////////////////// | |
532 | namespace boost { namespace spirit { namespace result_of | |
533 | { | |
534 | /////////////////////////////////////////////////////////////////////////// | |
535 | template <typename T> | |
536 | struct optional_value | |
537 | { | |
538 | typedef T type; | |
539 | }; | |
540 | ||
541 | template <typename T> | |
542 | struct optional_value<boost::optional<T> > | |
543 | { | |
544 | typedef T type; | |
545 | }; | |
546 | ||
547 | template <typename T> | |
548 | struct optional_value<boost::optional<T> const> | |
549 | { | |
550 | typedef T const type; | |
551 | }; | |
552 | ||
553 | template <> | |
554 | struct optional_value<unused_type> | |
555 | { | |
556 | typedef unused_type type; | |
557 | }; | |
558 | ||
559 | template <> | |
560 | struct optional_value<unused_type const> | |
561 | { | |
562 | typedef unused_type type; | |
563 | }; | |
564 | ||
565 | /////////////////////////////////////////////////////////////////////////// | |
566 | template <typename Container> | |
567 | struct begin | |
568 | : traits::container_iterator<Container> | |
569 | {}; | |
570 | ||
571 | template <typename Container> | |
572 | struct end | |
573 | : traits::container_iterator<Container> | |
574 | {}; | |
575 | ||
576 | template <typename Iterator> | |
577 | struct deref | |
578 | : traits::deref_iterator<Iterator> | |
579 | {}; | |
580 | ||
581 | template <> | |
582 | struct deref<unused_type const*> | |
583 | { | |
584 | typedef unused_type type; | |
585 | }; | |
586 | ||
587 | }}} | |
588 | ||
589 | #endif |