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/mpl/has_xxx.hpp> 19 #include <boost/mpl/bool.hpp> 20 #include <boost/optional.hpp> 21 #include <boost/variant.hpp> 22 #include <boost/preprocessor/cat.hpp> 23 #include <boost/preprocessor/repeat.hpp> 24 #include <boost/range/range_fwd.hpp> 25 #include <iterator> // for std::iterator_traits 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 Iterator type; 211 }; 212 213 template <> 214 struct container_iterator<unused_type> 215 { 216 typedef unused_type const* type; 217 }; 218 219 template <> 220 struct container_iterator<unused_type const> 221 { 222 typedef unused_type const* type; 223 }; 224 225 /////////////////////////////////////////////////////////////////////////// 226 template <typename T, typename Enable/* = void*/> 227 struct optional_attribute 228 { 229 typedef T const& type; 230 callboost::spirit::traits::optional_attribute231 static type call(T const& val) 232 { 233 return val; 234 } 235 is_validboost::spirit::traits::optional_attribute236 static bool is_valid(T const&) 237 { 238 return true; 239 } 240 }; 241 242 template <typename T> 243 struct optional_attribute<boost::optional<T> > 244 { 245 typedef T const& type; 246 callboost::spirit::traits::optional_attribute247 static type call(boost::optional<T> const& val) 248 { 249 return boost::get<T>(val); 250 } 251 is_validboost::spirit::traits::optional_attribute252 static bool is_valid(boost::optional<T> const& val) 253 { 254 return !!val; 255 } 256 }; 257 258 template <typename T> 259 typename optional_attribute<T>::type optional_value(T const & val)260 optional_value(T const& val) 261 { 262 return optional_attribute<T>::call(val); 263 } 264 optional_value(unused_type)265 inline unused_type optional_value(unused_type) 266 { 267 return unused; 268 } 269 270 template <typename T> has_optional_value(T const & val)271 bool has_optional_value(T const& val) 272 { 273 return optional_attribute<T>::is_valid(val); 274 } 275 has_optional_value(unused_type)276 inline bool has_optional_value(unused_type) 277 { 278 return true; 279 } 280 281 /////////////////////////////////////////////////////////////////////////// 282 template <typename Container, typename T> 283 bool push_back(Container& c, T const& val); 284 285 //[customization_push_back_default 286 template <typename Container, typename T, typename Enable/* = void*/> 287 struct push_back_container 288 { callboost::spirit::traits::push_back_container289 static bool call(Container& c, T const& val) 290 { 291 c.insert(c.end(), val); 292 return true; 293 } 294 }; 295 //] 296 297 template <typename Container, typename T> 298 struct push_back_container<optional<Container>, T> 299 { callboost::spirit::traits::push_back_container300 static bool call(boost::optional<Container>& c, T const& val) 301 { 302 if (!c) 303 c = Container(); 304 return push_back(boost::get<Container>(c), val); 305 } 306 }; 307 308 namespace detail 309 { 310 template <typename T> 311 struct push_back_visitor : public static_visitor<> 312 { 313 typedef bool result_type; 314 push_back_visitorboost::spirit::traits::detail::push_back_visitor315 push_back_visitor(T const& t) : t_(t) {} 316 317 template <typename Container> push_back_implboost::spirit::traits::detail::push_back_visitor318 bool push_back_impl(Container& c, mpl::true_) const 319 { 320 return push_back(c, t_); 321 } 322 323 template <typename T_> push_back_implboost::spirit::traits::detail::push_back_visitor324 bool push_back_impl(T_&, mpl::false_) const 325 { 326 // this variant doesn't hold a container 327 BOOST_ASSERT(false && "This variant doesn't hold a container"); 328 return false; 329 } 330 331 template <typename T_> operator ()boost::spirit::traits::detail::push_back_visitor332 bool operator()(T_& c) const 333 { 334 return push_back_impl(c, typename is_container<T_>::type()); 335 } 336 337 T const& t_; 338 }; 339 } 340 341 template <BOOST_VARIANT_ENUM_PARAMS(typename T_), typename T> 342 struct push_back_container<variant<BOOST_VARIANT_ENUM_PARAMS(T_)>, T> 343 { callboost::spirit::traits::push_back_container344 static bool call(variant<BOOST_VARIANT_ENUM_PARAMS(T_)>& c, T const& val) 345 { 346 return apply_visitor(detail::push_back_visitor<T>(val), c); 347 } 348 }; 349 350 template <typename Container, typename T> push_back(Container & c,T const & val)351 bool push_back(Container& c, T const& val) 352 { 353 return push_back_container<Container, T>::call(c, val); 354 } 355 356 //[customization_push_back_unused 357 template <typename Container> push_back(Container &,unused_type)358 bool push_back(Container&, unused_type) 359 { 360 return true; 361 } 362 //] 363 364 template <typename T> push_back(unused_type,T const &)365 bool push_back(unused_type, T const&) 366 { 367 return true; 368 } 369 push_back(unused_type,unused_type)370 inline bool push_back(unused_type, unused_type) 371 { 372 return true; 373 } 374 375 /////////////////////////////////////////////////////////////////////////// 376 template <typename Container, typename Enable/* = void*/> 377 struct is_empty_container 378 { callboost::spirit::traits::is_empty_container379 static bool call(Container const& c) 380 { 381 return c.empty(); 382 } 383 }; 384 385 template <typename Container> is_empty(Container const & c)386 bool is_empty(Container const& c) 387 { 388 return is_empty_container<Container>::call(c); 389 } 390 is_empty(unused_type)391 inline bool is_empty(unused_type) 392 { 393 return true; 394 } 395 396 /////////////////////////////////////////////////////////////////////////// 397 // Ensure the attribute is actually a container type 398 template <typename Container, typename Enable/* = void*/> 399 struct make_container_attribute 400 { callboost::spirit::traits::make_container_attribute401 static void call(Container&) 402 { 403 // for static types this function does nothing 404 } 405 }; 406 407 template <typename T> make_container(T & t)408 void make_container(T& t) 409 { 410 make_container_attribute<T>::call(t); 411 } 412 make_container(unused_type)413 inline void make_container(unused_type) 414 { 415 } 416 417 /////////////////////////////////////////////////////////////////////////// 418 template <typename Container, typename Enable/* = void*/> 419 struct begin_container 420 { callboost::spirit::traits::begin_container421 static typename container_iterator<Container>::type call(Container& c) 422 { 423 return c.begin(); 424 } 425 }; 426 427 template <typename Container> 428 typename spirit::result_of::begin<Container>::type begin(Container & c)429 begin(Container& c) 430 { 431 return begin_container<Container>::call(c); 432 } 433 434 inline unused_type const* begin(unused_type)435 begin(unused_type) 436 { 437 return &unused; 438 } 439 440 /////////////////////////////////////////////////////////////////////////// 441 template <typename Container, typename Enable/* = void*/> 442 struct end_container 443 { callboost::spirit::traits::end_container444 static typename container_iterator<Container>::type call(Container& c) 445 { 446 return c.end(); 447 } 448 }; 449 450 template <typename Container> 451 inline typename spirit::result_of::end<Container>::type end(Container & c)452 end(Container& c) 453 { 454 return end_container<Container>::call(c); 455 } 456 457 inline unused_type const* end(unused_type)458 end(unused_type) 459 { 460 return &unused; 461 } 462 463 /////////////////////////////////////////////////////////////////////////// 464 template <typename Iterator, typename Enable/* = void*/> 465 struct deref_iterator 466 { 467 typedef typename std::iterator_traits<Iterator>::reference type; callboost::spirit::traits::deref_iterator468 static type call(Iterator& it) 469 { 470 return *it; 471 } 472 }; 473 474 template <typename Iterator> 475 typename deref_iterator<Iterator>::type deref(Iterator & it)476 deref(Iterator& it) 477 { 478 return deref_iterator<Iterator>::call(it); 479 } 480 481 inline unused_type deref(unused_type const *)482 deref(unused_type const*) 483 { 484 return unused; 485 } 486 487 /////////////////////////////////////////////////////////////////////////// 488 template <typename Iterator, typename Enable/* = void*/> 489 struct next_iterator 490 { callboost::spirit::traits::next_iterator491 static void call(Iterator& it) 492 { 493 ++it; 494 } 495 }; 496 497 template <typename Iterator> next(Iterator & it)498 void next(Iterator& it) 499 { 500 next_iterator<Iterator>::call(it); 501 } 502 next(unused_type const *)503 inline void next(unused_type const*) 504 { 505 // do nothing 506 } 507 508 /////////////////////////////////////////////////////////////////////////// 509 template <typename Iterator, typename Enable/* = void*/> 510 struct compare_iterators 511 { callboost::spirit::traits::compare_iterators512 static bool call(Iterator const& it1, Iterator const& it2) 513 { 514 return it1 == it2; 515 } 516 }; 517 518 template <typename Iterator> compare(Iterator & it1,Iterator & it2)519 bool compare(Iterator& it1, Iterator& it2) 520 { 521 return compare_iterators<Iterator>::call(it1, it2); 522 } 523 compare(unused_type const *,unused_type const *)524 inline bool compare(unused_type const*, unused_type const*) 525 { 526 return false; 527 } 528 }}} 529 530 /////////////////////////////////////////////////////////////////////////////// 531 namespace boost { namespace spirit { namespace result_of 532 { 533 /////////////////////////////////////////////////////////////////////////// 534 template <typename T> 535 struct optional_value 536 { 537 typedef T type; 538 }; 539 540 template <typename T> 541 struct optional_value<boost::optional<T> > 542 { 543 typedef T type; 544 }; 545 546 template <typename T> 547 struct optional_value<boost::optional<T> const> 548 { 549 typedef T const type; 550 }; 551 552 template <> 553 struct optional_value<unused_type> 554 { 555 typedef unused_type type; 556 }; 557 558 template <> 559 struct optional_value<unused_type const> 560 { 561 typedef unused_type type; 562 }; 563 564 /////////////////////////////////////////////////////////////////////////// 565 template <typename Container> 566 struct begin 567 : traits::container_iterator<Container> 568 {}; 569 570 template <typename Container> 571 struct end 572 : traits::container_iterator<Container> 573 {}; 574 575 template <typename Iterator> 576 struct deref 577 : traits::deref_iterator<Iterator> 578 {}; 579 580 template <> 581 struct deref<unused_type const*> 582 { 583 typedef unused_type type; 584 }; 585 586 }}} 587 588 #endif 589