1 // Copyright (c) 2001-2011 Hartmut Kaiser 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 6 #if !defined(BOOST_SPIRIT_KARMA_UINT_FEB_23_2007_0840PM) 7 #define BOOST_SPIRIT_KARMA_UINT_FEB_23_2007_0840PM 8 9 #if defined(_MSC_VER) 10 #pragma once 11 #endif 12 13 #include <boost/limits.hpp> 14 #include <boost/config.hpp> 15 #include <boost/mpl/bool.hpp> 16 #include <boost/utility/enable_if.hpp> 17 18 #include <boost/spirit/home/support/common_terminals.hpp> 19 #include <boost/spirit/home/support/string_traits.hpp> 20 #include <boost/spirit/home/support/numeric_traits.hpp> 21 #include <boost/spirit/home/support/info.hpp> 22 #include <boost/spirit/home/support/char_class.hpp> 23 #include <boost/spirit/home/support/container.hpp> 24 #include <boost/spirit/home/support/detail/get_encoding.hpp> 25 #include <boost/spirit/home/support/detail/is_spirit_tag.hpp> 26 #include <boost/spirit/home/karma/meta_compiler.hpp> 27 #include <boost/spirit/home/karma/delimit_out.hpp> 28 #include <boost/spirit/home/karma/auxiliary/lazy.hpp> 29 #include <boost/spirit/home/karma/detail/get_casetag.hpp> 30 #include <boost/spirit/home/karma/detail/extract_from.hpp> 31 #include <boost/spirit/home/karma/detail/enable_lit.hpp> 32 #include <boost/spirit/home/karma/domain.hpp> 33 #include <boost/spirit/home/karma/numeric/detail/numeric_utils.hpp> 34 #include <boost/fusion/include/at.hpp> 35 #include <boost/fusion/include/value_at.hpp> 36 #include <boost/fusion/include/vector.hpp> 37 38 namespace boost { namespace spirit 39 { 40 namespace tag 41 { 42 template <typename T, unsigned Radix> 43 struct uint_generator 44 { 45 BOOST_SPIRIT_IS_TAG() 46 }; 47 } 48 49 namespace karma 50 { 51 /////////////////////////////////////////////////////////////////////// 52 // This one is the class that the user can instantiate directly in 53 // order to create a customized int generator 54 template <typename T = unsigned int, unsigned Radix = 10> 55 struct uint_generator 56 : spirit::terminal<tag::uint_generator<T, Radix> > 57 {}; 58 } 59 60 /////////////////////////////////////////////////////////////////////////// 61 // Enablers 62 /////////////////////////////////////////////////////////////////////////// 63 template <> 64 struct use_terminal<karma::domain, tag::ushort_> // enables ushort_ 65 : mpl::true_ {}; 66 67 template <> 68 struct use_terminal<karma::domain, tag::uint_> // enables uint_ 69 : mpl::true_ {}; 70 71 template <> 72 struct use_terminal<karma::domain, tag::ulong_> // enables ulong_ 73 : mpl::true_ {}; 74 75 template <> 76 struct use_terminal<karma::domain, tag::bin> // enables bin 77 : mpl::true_ {}; 78 79 template <> 80 struct use_terminal<karma::domain, tag::oct> // enables oct 81 : mpl::true_ {}; 82 83 template <> 84 struct use_terminal<karma::domain, tag::hex> // enables hex 85 : mpl::true_ {}; 86 87 #ifdef BOOST_HAS_LONG_LONG 88 template <> 89 struct use_terminal<karma::domain, tag::ulong_long> // enables ulong_long 90 : mpl::true_ {}; 91 #endif 92 93 /////////////////////////////////////////////////////////////////////////// 94 #if !defined(BOOST_NO_INTRINSIC_WCHAR_T) 95 template <> // enables lit(unsigned short(0)) 96 struct use_terminal<karma::domain, unsigned short> 97 : mpl::true_ {}; 98 #endif 99 100 template <> // enables lit(0U) 101 struct use_terminal<karma::domain, unsigned int> 102 : mpl::true_ {}; 103 104 template <> // enables lit(0UL) 105 struct use_terminal<karma::domain, unsigned long> 106 : mpl::true_ {}; 107 108 #ifdef BOOST_HAS_LONG_LONG 109 template <> // enables lit(0ULL) 110 struct use_terminal<karma::domain, boost::ulong_long_type> 111 : mpl::true_ {}; 112 #endif 113 114 /////////////////////////////////////////////////////////////////////////// 115 template <typename A0> 116 struct use_terminal<karma::domain // enables ushort_(...) 117 , terminal_ex<tag::ushort_, fusion::vector1<A0> > 118 > : mpl::true_ {}; 119 120 template <typename A0> 121 struct use_terminal<karma::domain // enables uint_(...) 122 , terminal_ex<tag::uint_, fusion::vector1<A0> > 123 > : mpl::true_ {}; 124 125 template <typename A0> 126 struct use_terminal<karma::domain // enables ulong_(...) 127 , terminal_ex<tag::ulong_, fusion::vector1<A0> > 128 > : mpl::true_ {}; 129 130 template <typename A0> 131 struct use_terminal<karma::domain // enables bin(...) 132 , terminal_ex<tag::bin, fusion::vector1<A0> > 133 > : mpl::true_ {}; 134 135 template <typename A0> 136 struct use_terminal<karma::domain // enables oct(...) 137 , terminal_ex<tag::oct, fusion::vector1<A0> > 138 > : mpl::true_ {}; 139 140 template <typename A0> 141 struct use_terminal<karma::domain // enables hex(...) 142 , terminal_ex<tag::hex, fusion::vector1<A0> > 143 > : mpl::true_ {}; 144 145 #ifdef BOOST_HAS_LONG_LONG 146 template <typename A0> 147 struct use_terminal<karma::domain // enables ulong_long(...) 148 , terminal_ex<tag::ulong_long, fusion::vector1<A0> > 149 > : mpl::true_ {}; 150 #endif 151 152 /////////////////////////////////////////////////////////////////////////// 153 template <> // enables *lazy* ushort_(...) 154 struct use_lazy_terminal<karma::domain, tag::ushort_, 1> 155 : mpl::true_ {}; 156 157 template <> // enables *lazy* uint_(...) 158 struct use_lazy_terminal<karma::domain, tag::uint_, 1> 159 : mpl::true_ {}; 160 161 template <> // enables *lazy* ulong_(...) 162 struct use_lazy_terminal<karma::domain, tag::ulong_, 1> 163 : mpl::true_ {}; 164 165 template <> // enables *lazy* bin(...) 166 struct use_lazy_terminal<karma::domain, tag::bin, 1> 167 : mpl::true_ {}; 168 169 template <> // enables *lazy* oct(...) 170 struct use_lazy_terminal<karma::domain, tag::oct, 1> 171 : mpl::true_ {}; 172 173 template <> // enables *lazy* hex(...) 174 struct use_lazy_terminal<karma::domain, tag::hex, 1> 175 : mpl::true_ {}; 176 177 #ifdef BOOST_HAS_LONG_LONG 178 template <> // enables *lazy* ulong_long(...) 179 struct use_lazy_terminal<karma::domain, tag::ulong_long, 1> 180 : mpl::true_ {}; 181 #endif 182 183 /////////////////////////////////////////////////////////////////////////// 184 // enables any custom uint_generator 185 template <typename T, unsigned Radix> 186 struct use_terminal<karma::domain, tag::uint_generator<T, Radix> > 187 : mpl::true_ {}; 188 189 // enables any custom uint_generator(...) 190 template <typename T, unsigned Radix, typename A0> 191 struct use_terminal<karma::domain 192 , terminal_ex<tag::uint_generator<T, Radix>, fusion::vector1<A0> > 193 > : mpl::true_ {}; 194 195 // enables *lazy* custom uint_generator 196 template <typename T, unsigned Radix> 197 struct use_lazy_terminal< 198 karma::domain 199 , tag::uint_generator<T, Radix> 200 , 1 // arity 201 > : mpl::true_ {}; 202 203 // enables lit(uint) 204 template <typename A0> 205 struct use_terminal<karma::domain 206 , terminal_ex<tag::lit, fusion::vector1<A0> > 207 , typename enable_if<traits::is_uint<A0> >::type> 208 : mpl::true_ {}; 209 }} 210 211 /////////////////////////////////////////////////////////////////////////////// 212 namespace boost { namespace spirit { namespace karma 213 { 214 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS 215 using spirit::ushort_; 216 using spirit::uint_; 217 using spirit::ulong_; 218 #ifdef BOOST_HAS_LONG_LONG 219 using spirit::ulong_long; 220 #endif 221 using spirit::bin; 222 using spirit::oct; 223 using spirit::hex; 224 225 using spirit::lit; // lit(1U) is equivalent to 1U 226 #endif 227 228 using spirit::ushort_type; 229 using spirit::uint_type; 230 using spirit::ulong_type; 231 #ifdef BOOST_HAS_LONG_LONG 232 using spirit::ulong_long_type; 233 #endif 234 using spirit::bin_type; 235 using spirit::oct_type; 236 using spirit::hex_type; 237 238 using spirit::lit_type; 239 240 /////////////////////////////////////////////////////////////////////////// 241 // This specialization is used for unsigned int generators not having a 242 // direct initializer: uint_, ulong_ etc. These generators must be used in 243 // conjunction with an Attribute. 244 /////////////////////////////////////////////////////////////////////////// 245 template <typename T, typename CharEncoding, typename Tag, unsigned Radix> 246 struct any_uint_generator 247 : primitive_generator<any_uint_generator<T, CharEncoding, Tag, Radix> > 248 { 249 template <typename Context, typename Unused> 250 struct attribute 251 { 252 typedef T type; 253 }; 254 255 // check template Attribute 'Radix' for validity 256 BOOST_SPIRIT_ASSERT_MSG( 257 Radix >= 2 && Radix <= 36, not_supported_radix, ()); 258 259 BOOST_SPIRIT_ASSERT_MSG( 260 // the following is a workaround for STLPort, where the simpler 261 // `!std::numeric_limits<T>::is_signed` wouldn't compile 262 mpl::not_<mpl::bool_<std::numeric_limits<T>::is_signed> >::value, 263 signed_unsigned_mismatch, ()); 264 265 // int has a Attribute attached 266 template <typename OutputIterator, typename Context, typename Delimiter 267 , typename Attribute> 268 static bool generateboost::spirit::karma::any_uint_generator269 generate(OutputIterator& sink, Context& context, Delimiter const& d 270 , Attribute const& attr) 271 { 272 if (!traits::has_optional_value(attr)) 273 return false; // fail if it's an uninitialized optional 274 275 return uint_inserter<Radix, CharEncoding, Tag>:: 276 call(sink, traits::extract_from<T>(attr, context)) && 277 delimit_out(sink, d); // always do post-delimiting 278 } 279 280 // this int has no Attribute attached, it needs to have been 281 // initialized from a direct literal 282 template <typename OutputIterator, typename Context, typename Delimiter> 283 static bool generateboost::spirit::karma::any_uint_generator284 generate(OutputIterator&, Context&, Delimiter const&, unused_type) 285 { 286 // It is not possible (doesn't make sense) to use numeric generators 287 // without providing any attribute, as the generator doesn't 'know' 288 // what to output. The following assertion fires if this situation 289 // is detected in your code. 290 BOOST_SPIRIT_ASSERT_FAIL(OutputIterator, uint_not_usable_without_attribute, ()); 291 return false; 292 } 293 294 template <typename Context> whatboost::spirit::karma::any_uint_generator295 static info what(Context const& /*context*/) 296 { 297 return info("unsigned-integer"); 298 } 299 }; 300 301 /////////////////////////////////////////////////////////////////////////// 302 // This specialization is used for unsigned int generators having a direct 303 // initializer: uint_(10), ulong_(20) etc. 304 /////////////////////////////////////////////////////////////////////////// 305 template < 306 typename T, typename CharEncoding, typename Tag, unsigned Radix 307 , bool no_attribute> 308 struct literal_uint_generator 309 : primitive_generator<literal_uint_generator<T, CharEncoding, Tag, Radix 310 , no_attribute> > 311 { 312 template <typename Context, typename Unused = unused_type> 313 struct attribute 314 : mpl::if_c<no_attribute, unused_type, T> 315 {}; 316 literal_uint_generatorboost::spirit::karma::literal_uint_generator317 literal_uint_generator(typename add_const<T>::type n) 318 : n_(n) {} 319 320 // check template Attribute 'Radix' for validity 321 BOOST_SPIRIT_ASSERT_MSG( 322 Radix >= 2 && Radix <= 36, not_supported_radix, ()); 323 324 BOOST_SPIRIT_ASSERT_MSG( 325 // the following is a workaround for STLPort, where the simpler 326 // `!std::numeric_limits<T>::is_signed wouldn't` compile 327 mpl::not_<mpl::bool_<std::numeric_limits<T>::is_signed> >::value, 328 signed_unsigned_mismatch, ()); 329 330 // A uint(1U) which additionally has an associated attribute emits 331 // its immediate literal only if it matches the attribute, otherwise 332 // it fails. 333 template <typename OutputIterator, typename Context, typename Delimiter 334 , typename Attribute> generateboost::spirit::karma::literal_uint_generator335 bool generate(OutputIterator& sink, Context& context 336 , Delimiter const& d, Attribute const& attr) const 337 { 338 typedef typename attribute<Context>::type attribute_type; 339 if (!traits::has_optional_value(attr) || 340 n_ != traits::extract_from<attribute_type>(attr, context)) 341 { 342 return false; 343 } 344 return uint_inserter<Radix, CharEncoding, Tag>::call(sink, n_) && 345 delimit_out(sink, d); // always do post-delimiting 346 } 347 348 // A uint(1U) without any associated attribute just emits its 349 // immediate literal 350 template <typename OutputIterator, typename Context, typename Delimiter> generateboost::spirit::karma::literal_uint_generator351 bool generate(OutputIterator& sink, Context&, Delimiter const& d 352 , unused_type) const 353 { 354 return uint_inserter<Radix, CharEncoding, Tag>::call(sink, n_) && 355 delimit_out(sink, d); // always do post-delimiting 356 } 357 358 template <typename Context> whatboost::spirit::karma::literal_uint_generator359 static info what(Context const& /*context*/) 360 { 361 return info("unsigned-integer"); 362 } 363 364 T n_; 365 }; 366 367 /////////////////////////////////////////////////////////////////////////// 368 // Generator generators: make_xxx function (objects) 369 /////////////////////////////////////////////////////////////////////////// 370 namespace detail 371 { 372 template <typename T, typename Modifiers, unsigned Radix = 10> 373 struct make_uint 374 { 375 static bool const lower = 376 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value; 377 static bool const upper = 378 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value; 379 380 typedef any_uint_generator< 381 T 382 , typename spirit::detail::get_encoding_with_case< 383 Modifiers, unused_type, lower || upper>::type 384 , typename detail::get_casetag<Modifiers, lower || upper>::type 385 , Radix 386 > result_type; 387 operator ()boost::spirit::karma::detail::make_uint388 result_type operator()(unused_type, unused_type) const 389 { 390 return result_type(); 391 } 392 }; 393 } 394 395 /////////////////////////////////////////////////////////////////////////// 396 template <typename Modifiers> 397 struct make_primitive<tag::ushort_, Modifiers> 398 : detail::make_uint<unsigned short, Modifiers> {}; 399 400 template <typename Modifiers> 401 struct make_primitive<tag::uint_, Modifiers> 402 : detail::make_uint<unsigned int, Modifiers> {}; 403 404 template <typename Modifiers> 405 struct make_primitive<tag::ulong_, Modifiers> 406 : detail::make_uint<unsigned long, Modifiers> {}; 407 408 template <typename Modifiers> 409 struct make_primitive<tag::bin, Modifiers> 410 : detail::make_uint<unsigned, Modifiers, 2> {}; 411 412 template <typename Modifiers> 413 struct make_primitive<tag::oct, Modifiers> 414 : detail::make_uint<unsigned, Modifiers, 8> {}; 415 416 template <typename Modifiers> 417 struct make_primitive<tag::hex, Modifiers> 418 : detail::make_uint<unsigned, Modifiers, 16> {}; 419 420 #ifdef BOOST_HAS_LONG_LONG 421 template <typename Modifiers> 422 struct make_primitive<tag::ulong_long, Modifiers> 423 : detail::make_uint<boost::ulong_long_type, Modifiers> {}; 424 #endif 425 426 template <typename T, unsigned Radix, typename Modifiers> 427 struct make_primitive<tag::uint_generator<T, Radix>, Modifiers> 428 : detail::make_uint<typename remove_const<T>::type, Modifiers, Radix> {}; 429 430 /////////////////////////////////////////////////////////////////////////// 431 namespace detail 432 { 433 template <typename T, typename Modifiers, unsigned Radix = 10> 434 struct make_uint_direct 435 { 436 static bool const lower = 437 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value; 438 static bool const upper = 439 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value; 440 441 typedef literal_uint_generator< 442 T 443 , typename spirit::detail::get_encoding_with_case< 444 Modifiers, unused_type, lower || upper>::type 445 , typename detail::get_casetag<Modifiers, lower || upper>::type 446 , Radix, false 447 > result_type; 448 449 template <typename Terminal> operator ()boost::spirit::karma::detail::make_uint_direct450 result_type operator()(Terminal const& term, unused_type) const 451 { 452 return result_type(fusion::at_c<0>(term.args)); 453 } 454 }; 455 } 456 457 template <typename Modifiers, typename A0> 458 struct make_primitive< 459 terminal_ex<tag::ushort_, fusion::vector1<A0> >, Modifiers> 460 : detail::make_uint_direct<unsigned short, Modifiers> {}; 461 462 template <typename Modifiers, typename A0> 463 struct make_primitive< 464 terminal_ex<tag::uint_, fusion::vector1<A0> >, Modifiers> 465 : detail::make_uint_direct<unsigned int, Modifiers> {}; 466 467 template <typename Modifiers, typename A0> 468 struct make_primitive< 469 terminal_ex<tag::ulong_, fusion::vector1<A0> >, Modifiers> 470 : detail::make_uint_direct<unsigned long, Modifiers> {}; 471 472 template <typename Modifiers, typename A0> 473 struct make_primitive< 474 terminal_ex<tag::bin, fusion::vector1<A0> >, Modifiers> 475 : detail::make_uint_direct<unsigned, Modifiers, 2> {}; 476 477 template <typename Modifiers, typename A0> 478 struct make_primitive< 479 terminal_ex<tag::oct, fusion::vector1<A0> >, Modifiers> 480 : detail::make_uint_direct<unsigned, Modifiers, 8> {}; 481 482 template <typename Modifiers, typename A0> 483 struct make_primitive< 484 terminal_ex<tag::hex, fusion::vector1<A0> >, Modifiers> 485 : detail::make_uint_direct<unsigned, Modifiers, 16> {}; 486 487 #ifdef BOOST_HAS_LONG_LONG 488 template <typename Modifiers, typename A0> 489 struct make_primitive< 490 terminal_ex<tag::ulong_long, fusion::vector1<A0> >, Modifiers> 491 : detail::make_uint_direct<boost::ulong_long_type, Modifiers> {}; 492 #endif 493 494 template <typename T, unsigned Radix, typename A0, typename Modifiers> 495 struct make_primitive< 496 terminal_ex<tag::uint_generator<T, Radix>, fusion::vector1<A0> > 497 , Modifiers> 498 : detail::make_uint_direct<typename remove_const<T>::type, Modifiers, Radix> 499 {}; 500 501 /////////////////////////////////////////////////////////////////////////// 502 namespace detail 503 { 504 template <typename T, typename Modifiers> 505 struct basic_uint_literal 506 { 507 static bool const lower = 508 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value; 509 static bool const upper = 510 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value; 511 512 typedef literal_uint_generator< 513 T 514 , typename spirit::detail::get_encoding_with_case< 515 Modifiers, unused_type, lower || upper>::type 516 , typename detail::get_casetag<Modifiers, lower || upper>::type 517 , 10, true 518 > result_type; 519 520 template <typename T_> operator ()boost::spirit::karma::detail::basic_uint_literal521 result_type operator()(T_ i, unused_type) const 522 { 523 return result_type(i); 524 } 525 }; 526 } 527 528 #if !defined(BOOST_NO_INTRINSIC_WCHAR_T) 529 template <typename Modifiers> 530 struct make_primitive<unsigned short, Modifiers> 531 : detail::basic_uint_literal<unsigned short, Modifiers> {}; 532 #endif 533 534 template <typename Modifiers> 535 struct make_primitive<unsigned int, Modifiers> 536 : detail::basic_uint_literal<unsigned int, Modifiers> {}; 537 538 template <typename Modifiers> 539 struct make_primitive<unsigned long, Modifiers> 540 : detail::basic_uint_literal<unsigned long, Modifiers> {}; 541 542 #ifdef BOOST_HAS_LONG_LONG 543 template <typename Modifiers> 544 struct make_primitive<boost::ulong_long_type, Modifiers> 545 : detail::basic_uint_literal<boost::ulong_long_type, Modifiers> {}; 546 #endif 547 548 // lit(uint) 549 template <typename Modifiers, typename A0> 550 struct make_primitive< 551 terminal_ex<tag::lit, fusion::vector1<A0> > 552 , Modifiers 553 , typename enable_if<traits::is_uint<A0> >::type> 554 { 555 static bool const lower = 556 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value; 557 static bool const upper = 558 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value; 559 560 typedef literal_uint_generator< 561 typename remove_const<A0>::type 562 , typename spirit::detail::get_encoding_with_case< 563 Modifiers, unused_type, lower || upper>::type 564 , typename detail::get_casetag<Modifiers, lower || upper>::type 565 , 10, true 566 > result_type; 567 568 template <typename Terminal> operator ()boost::spirit::karma::make_primitive569 result_type operator()(Terminal const& term, unused_type) const 570 { 571 return result_type(fusion::at_c<0>(term.args)); 572 } 573 }; 574 }}} 575 576 #endif 577