1 // Copyright Kevlin Henney, 2000-2005. 2 // Copyright Alexander Nasonov, 2006-2010. 3 // Copyright Antony Polukhin, 2011-2021. 4 // 5 // Distributed under the Boost Software License, Version 1.0. (See 6 // accompanying file LICENSE_1_0.txt or copy at 7 // http://www.boost.org/LICENSE_1_0.txt) 8 // 9 // what: lexical_cast custom keyword cast 10 // who: contributed by Kevlin Henney, 11 // enhanced with contributions from Terje Slettebo, 12 // with additional fixes and suggestions from Gennaro Prota, 13 // Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov, 14 // Alexander Nasonov, Antony Polukhin, Justin Viiret, Michael Hofmann, 15 // Cheng Yang, Matthew Bradbury, David W. Birdsall, Pavel Korzh and other Boosters 16 // when: November 2000, March 2003, June 2005, June 2006, March 2011 - 2014 17 18 #ifndef BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP 19 #define BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP 20 21 #include <boost/config.hpp> 22 #ifdef BOOST_HAS_PRAGMA_ONCE 23 # pragma once 24 #endif 25 26 #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) 27 #define BOOST_LCAST_NO_WCHAR_T 28 #endif 29 30 #include <cstddef> 31 #include <string> 32 #include <boost/limits.hpp> 33 #include <boost/type_traits/integral_constant.hpp> 34 #include <boost/type_traits/type_identity.hpp> 35 #include <boost/type_traits/conditional.hpp> 36 #include <boost/type_traits/is_integral.hpp> 37 #include <boost/type_traits/is_float.hpp> 38 #include <boost/type_traits/has_left_shift.hpp> 39 #include <boost/type_traits/has_right_shift.hpp> 40 #include <boost/static_assert.hpp> 41 #include <boost/detail/lcast_precision.hpp> 42 43 #include <boost/lexical_cast/detail/widest_char.hpp> 44 #include <boost/lexical_cast/detail/is_character.hpp> 45 46 #ifndef BOOST_NO_CXX11_HDR_ARRAY 47 #include <array> 48 #endif 49 50 #include <boost/array.hpp> 51 #include <boost/range/iterator_range_core.hpp> 52 #include <boost/container/container_fwd.hpp> 53 54 #include <boost/lexical_cast/detail/converter_lexical_streams.hpp> 55 56 namespace boost { 57 58 namespace detail // normalize_single_byte_char<Char> 59 { 60 // Converts signed/unsigned char to char 61 template < class Char > 62 struct normalize_single_byte_char 63 { 64 typedef Char type; 65 }; 66 67 template <> 68 struct normalize_single_byte_char< signed char > 69 { 70 typedef char type; 71 }; 72 73 template <> 74 struct normalize_single_byte_char< unsigned char > 75 { 76 typedef char type; 77 }; 78 } 79 80 namespace detail // deduce_character_type_later<T> 81 { 82 // Helper type, meaning that stram character for T must be deduced 83 // at Stage 2 (See deduce_source_char<T> and deduce_target_char<T>) 84 template < class T > struct deduce_character_type_later {}; 85 } 86 87 namespace detail // stream_char_common<T> 88 { 89 // Selectors to choose stream character type (common for Source and Target) 90 // Returns one of char, wchar_t, char16_t, char32_t or deduce_character_type_later<T> types 91 // Executed on Stage 1 (See deduce_source_char<T> and deduce_target_char<T>) 92 template < typename Type > 93 struct stream_char_common: public boost::conditional< 94 boost::detail::is_character< Type >::value, 95 Type, 96 boost::detail::deduce_character_type_later< Type > 97 > {}; 98 99 template < typename Char > 100 struct stream_char_common< Char* >: public boost::conditional< 101 boost::detail::is_character< Char >::value, 102 Char, 103 boost::detail::deduce_character_type_later< Char* > 104 > {}; 105 106 template < typename Char > 107 struct stream_char_common< const Char* >: public boost::conditional< 108 boost::detail::is_character< Char >::value, 109 Char, 110 boost::detail::deduce_character_type_later< const Char* > 111 > {}; 112 113 template < typename Char > 114 struct stream_char_common< boost::iterator_range< Char* > >: public boost::conditional< 115 boost::detail::is_character< Char >::value, 116 Char, 117 boost::detail::deduce_character_type_later< boost::iterator_range< Char* > > 118 > {}; 119 120 template < typename Char > 121 struct stream_char_common< boost::iterator_range< const Char* > >: public boost::conditional< 122 boost::detail::is_character< Char >::value, 123 Char, 124 boost::detail::deduce_character_type_later< boost::iterator_range< const Char* > > 125 > {}; 126 127 template < class Char, class Traits, class Alloc > 128 struct stream_char_common< std::basic_string< Char, Traits, Alloc > > 129 { 130 typedef Char type; 131 }; 132 133 template < class Char, class Traits, class Alloc > 134 struct stream_char_common< boost::container::basic_string< Char, Traits, Alloc > > 135 { 136 typedef Char type; 137 }; 138 139 template < typename Char, std::size_t N > 140 struct stream_char_common< boost::array< Char, N > >: public boost::conditional< 141 boost::detail::is_character< Char >::value, 142 Char, 143 boost::detail::deduce_character_type_later< boost::array< Char, N > > 144 > {}; 145 146 template < typename Char, std::size_t N > 147 struct stream_char_common< boost::array< const Char, N > >: public boost::conditional< 148 boost::detail::is_character< Char >::value, 149 Char, 150 boost::detail::deduce_character_type_later< boost::array< const Char, N > > 151 > {}; 152 153 #ifndef BOOST_NO_CXX11_HDR_ARRAY 154 template < typename Char, std::size_t N > 155 struct stream_char_common< std::array<Char, N > >: public boost::conditional< 156 boost::detail::is_character< Char >::value, 157 Char, 158 boost::detail::deduce_character_type_later< std::array< Char, N > > 159 > {}; 160 161 template < typename Char, std::size_t N > 162 struct stream_char_common< std::array< const Char, N > >: public boost::conditional< 163 boost::detail::is_character< Char >::value, 164 Char, 165 boost::detail::deduce_character_type_later< std::array< const Char, N > > 166 > {}; 167 #endif 168 169 #ifdef BOOST_HAS_INT128 170 template <> struct stream_char_common< boost::int128_type >: public boost::type_identity< char > {}; 171 template <> struct stream_char_common< boost::uint128_type >: public boost::type_identity< char > {}; 172 #endif 173 174 #if !defined(BOOST_LCAST_NO_WCHAR_T) && defined(BOOST_NO_INTRINSIC_WCHAR_T) 175 template <> 176 struct stream_char_common< wchar_t > 177 { 178 typedef char type; 179 }; 180 #endif 181 } 182 183 namespace detail // deduce_source_char_impl<T> 184 { 185 // If type T is `deduce_character_type_later` type, then tries to deduce 186 // character type using boost::has_left_shift<T> metafunction. 187 // Otherwise supplied type T is a character type, that must be normalized 188 // using normalize_single_byte_char<Char>. 189 // Executed at Stage 2 (See deduce_source_char<T> and deduce_target_char<T>) 190 template < class Char > 191 struct deduce_source_char_impl 192 { 193 typedef BOOST_DEDUCED_TYPENAME boost::detail::normalize_single_byte_char< Char >::type type; 194 }; 195 196 template < class T > 197 struct deduce_source_char_impl< deduce_character_type_later< T > > 198 { 199 typedef boost::has_left_shift< std::basic_ostream< char >, T > result_t; 200 201 #if defined(BOOST_LCAST_NO_WCHAR_T) 202 BOOST_STATIC_ASSERT_MSG((result_t::value), 203 "Source type is not std::ostream`able and std::wostream`s are not supported by your STL implementation"); 204 typedef char type; 205 #else 206 typedef BOOST_DEDUCED_TYPENAME boost::conditional< 207 result_t::value, char, wchar_t 208 >::type type; 209 210 BOOST_STATIC_ASSERT_MSG((result_t::value || boost::has_left_shift< std::basic_ostream< type >, T >::value), 211 "Source type is neither std::ostream`able nor std::wostream`able"); 212 #endif 213 }; 214 } 215 216 namespace detail // deduce_target_char_impl<T> 217 { 218 // If type T is `deduce_character_type_later` type, then tries to deduce 219 // character type using boost::has_right_shift<T> metafunction. 220 // Otherwise supplied type T is a character type, that must be normalized 221 // using normalize_single_byte_char<Char>. 222 // Executed at Stage 2 (See deduce_source_char<T> and deduce_target_char<T>) 223 template < class Char > 224 struct deduce_target_char_impl 225 { 226 typedef BOOST_DEDUCED_TYPENAME normalize_single_byte_char< Char >::type type; 227 }; 228 229 template < class T > 230 struct deduce_target_char_impl< deduce_character_type_later<T> > 231 { 232 typedef boost::has_right_shift<std::basic_istream<char>, T > result_t; 233 234 #if defined(BOOST_LCAST_NO_WCHAR_T) 235 BOOST_STATIC_ASSERT_MSG((result_t::value), 236 "Target type is not std::istream`able and std::wistream`s are not supported by your STL implementation"); 237 typedef char type; 238 #else 239 typedef BOOST_DEDUCED_TYPENAME boost::conditional< 240 result_t::value, char, wchar_t 241 >::type type; 242 243 BOOST_STATIC_ASSERT_MSG((result_t::value || boost::has_right_shift<std::basic_istream<wchar_t>, T >::value), 244 "Target type is neither std::istream`able nor std::wistream`able"); 245 #endif 246 }; 247 } 248 249 namespace detail // deduce_target_char<T> and deduce_source_char<T> 250 { 251 // We deduce stream character types in two stages. 252 // 253 // Stage 1 is common for Target and Source. At Stage 1 we get 254 // non normalized character type (may contain unsigned/signed char) 255 // or deduce_character_type_later<T> where T is the original type. 256 // Stage 1 is executed by stream_char_common<T> 257 // 258 // At Stage 2 we normalize character types or try to deduce character 259 // type using metafunctions. 260 // Stage 2 is executed by deduce_target_char_impl<T> and 261 // deduce_source_char_impl<T> 262 // 263 // deduce_target_char<T> and deduce_source_char<T> functions combine 264 // both stages 265 266 template < class T > 267 struct deduce_target_char 268 { 269 typedef BOOST_DEDUCED_TYPENAME stream_char_common< T >::type stage1_type; 270 typedef BOOST_DEDUCED_TYPENAME deduce_target_char_impl< stage1_type >::type stage2_type; 271 272 typedef stage2_type type; 273 }; 274 275 template < class T > 276 struct deduce_source_char 277 { 278 typedef BOOST_DEDUCED_TYPENAME stream_char_common< T >::type stage1_type; 279 typedef BOOST_DEDUCED_TYPENAME deduce_source_char_impl< stage1_type >::type stage2_type; 280 281 typedef stage2_type type; 282 }; 283 } 284 285 namespace detail // extract_char_traits template 286 { 287 // We are attempting to get char_traits<> from T 288 // template parameter. Otherwise we'll be using std::char_traits<Char> 289 template < class Char, class T > 290 struct extract_char_traits 291 : boost::false_type 292 { 293 typedef std::char_traits< Char > trait_t; 294 }; 295 296 template < class Char, class Traits, class Alloc > 297 struct extract_char_traits< Char, std::basic_string< Char, Traits, Alloc > > 298 : boost::true_type 299 { 300 typedef Traits trait_t; 301 }; 302 303 template < class Char, class Traits, class Alloc> 304 struct extract_char_traits< Char, boost::container::basic_string< Char, Traits, Alloc > > 305 : boost::true_type 306 { 307 typedef Traits trait_t; 308 }; 309 } 310 311 namespace detail // array_to_pointer_decay<T> 312 { 313 template<class T> 314 struct array_to_pointer_decay 315 { 316 typedef T type; 317 }; 318 319 template<class T, std::size_t N> 320 struct array_to_pointer_decay<T[N]> 321 { 322 typedef const T * type; 323 }; 324 } 325 326 namespace detail // lcast_src_length 327 { 328 // Return max. length of string representation of Source; 329 template< class Source, // Source type of lexical_cast. 330 class Enable = void // helper type 331 > 332 struct lcast_src_length 333 { 334 BOOST_STATIC_CONSTANT(std::size_t, value = 1); 335 }; 336 337 // Helper for integral types. 338 // Notes on length calculation: 339 // Max length for 32bit int with grouping "\1" and thousands_sep ',': 340 // "-2,1,4,7,4,8,3,6,4,7" 341 // ^ - is_signed 342 // ^ - 1 digit not counted by digits10 343 // ^^^^^^^^^^^^^^^^^^ - digits10 * 2 344 // 345 // Constant is_specialized is used instead of constant 1 346 // to prevent buffer overflow in a rare case when 347 // <boost/limits.hpp> doesn't add missing specialization for 348 // numeric_limits<T> for some integral type T. 349 // When is_specialized is false, the whole expression is 0. 350 template <class Source> 351 struct lcast_src_length< 352 Source, BOOST_DEDUCED_TYPENAME boost::enable_if<boost::is_integral<Source> >::type 353 > 354 { 355 #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS 356 BOOST_STATIC_CONSTANT(std::size_t, value = 357 std::numeric_limits<Source>::is_signed + 358 std::numeric_limits<Source>::is_specialized + /* == 1 */ 359 std::numeric_limits<Source>::digits10 * 2 360 ); 361 #else 362 BOOST_STATIC_CONSTANT(std::size_t, value = 156); 363 BOOST_STATIC_ASSERT(sizeof(Source) * CHAR_BIT <= 256); 364 #endif 365 }; 366 367 // Helper for floating point types. 368 // -1.23456789e-123456 369 // ^ sign 370 // ^ leading digit 371 // ^ decimal point 372 // ^^^^^^^^ lcast_precision<Source>::value 373 // ^ "e" 374 // ^ exponent sign 375 // ^^^^^^ exponent (assumed 6 or less digits) 376 // sign + leading digit + decimal point + "e" + exponent sign == 5 377 template<class Source> 378 struct lcast_src_length< 379 Source, BOOST_DEDUCED_TYPENAME boost::enable_if<boost::is_float<Source> >::type 380 > 381 { 382 383 #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION 384 BOOST_STATIC_ASSERT( 385 std::numeric_limits<Source>::max_exponent10 <= 999999L && 386 std::numeric_limits<Source>::min_exponent10 >= -999999L 387 ); 388 389 BOOST_STATIC_CONSTANT(std::size_t, value = 390 5 + lcast_precision<Source>::value + 6 391 ); 392 #else // #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION 393 BOOST_STATIC_CONSTANT(std::size_t, value = 156); 394 #endif // #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION 395 }; 396 } 397 398 namespace detail // lexical_cast_stream_traits<Source, Target> 399 { 400 template <class Source, class Target> 401 struct lexical_cast_stream_traits { 402 typedef BOOST_DEDUCED_TYPENAME boost::detail::array_to_pointer_decay<Source>::type src; 403 typedef BOOST_DEDUCED_TYPENAME boost::remove_cv<src>::type no_cv_src; 404 405 typedef boost::detail::deduce_source_char<no_cv_src> deduce_src_char_metafunc; 406 typedef BOOST_DEDUCED_TYPENAME deduce_src_char_metafunc::type src_char_t; 407 typedef BOOST_DEDUCED_TYPENAME boost::detail::deduce_target_char<Target>::type target_char_t; 408 409 typedef BOOST_DEDUCED_TYPENAME boost::detail::widest_char< 410 target_char_t, src_char_t 411 >::type char_type; 412 413 #if !defined(BOOST_NO_CXX11_CHAR16_T) && defined(BOOST_NO_CXX11_UNICODE_LITERALS) 414 BOOST_STATIC_ASSERT_MSG(( !boost::is_same<char16_t, src_char_t>::value 415 && !boost::is_same<char16_t, target_char_t>::value), 416 "Your compiler does not have full support for char16_t" ); 417 #endif 418 #if !defined(BOOST_NO_CXX11_CHAR32_T) && defined(BOOST_NO_CXX11_UNICODE_LITERALS) 419 BOOST_STATIC_ASSERT_MSG(( !boost::is_same<char32_t, src_char_t>::value 420 && !boost::is_same<char32_t, target_char_t>::value), 421 "Your compiler does not have full support for char32_t" ); 422 #endif 423 424 typedef BOOST_DEDUCED_TYPENAME boost::conditional< 425 boost::detail::extract_char_traits<char_type, Target>::value, 426 BOOST_DEDUCED_TYPENAME boost::detail::extract_char_traits<char_type, Target>, 427 BOOST_DEDUCED_TYPENAME boost::detail::extract_char_traits<char_type, no_cv_src> 428 >::type::trait_t traits; 429 430 typedef boost::integral_constant< 431 bool, 432 boost::is_same<char, src_char_t>::value && // source is not a wide character based type 433 (sizeof(char) != sizeof(target_char_t)) && // target type is based on wide character 434 (!(boost::detail::is_character<no_cv_src>::value)) 435 > is_string_widening_required_t; 436 437 typedef boost::integral_constant< 438 bool, 439 !(boost::is_integral<no_cv_src>::value || 440 boost::detail::is_character< 441 BOOST_DEDUCED_TYPENAME deduce_src_char_metafunc::stage1_type // if we did not get character type at stage1 442 >::value // then we have no optimization for that type 443 ) 444 > is_source_input_not_optimized_t; 445 446 // If we have an optimized conversion for 447 // Source, we do not need to construct stringbuf. 448 BOOST_STATIC_CONSTANT(bool, requires_stringbuf = 449 (is_string_widening_required_t::value || is_source_input_not_optimized_t::value) 450 ); 451 452 typedef boost::detail::lcast_src_length<no_cv_src> len_t; 453 }; 454 } 455 456 namespace detail 457 { 458 template<typename Target, typename Source> 459 struct lexical_converter_impl 460 { 461 typedef lexical_cast_stream_traits<Source, Target> stream_trait; 462 463 typedef detail::lexical_istream_limited_src< 464 BOOST_DEDUCED_TYPENAME stream_trait::char_type, 465 BOOST_DEDUCED_TYPENAME stream_trait::traits, 466 stream_trait::requires_stringbuf, 467 stream_trait::len_t::value + 1 468 > i_interpreter_type; 469 470 typedef detail::lexical_ostream_limited_src< 471 BOOST_DEDUCED_TYPENAME stream_trait::char_type, 472 BOOST_DEDUCED_TYPENAME stream_trait::traits 473 > o_interpreter_type; 474 try_convertboost::detail::lexical_converter_impl475 static inline bool try_convert(const Source& arg, Target& result) { 476 i_interpreter_type i_interpreter; 477 478 // Disabling ADL, by directly specifying operators. 479 if (!(i_interpreter.operator <<(arg))) 480 return false; 481 482 o_interpreter_type out(i_interpreter.cbegin(), i_interpreter.cend()); 483 484 // Disabling ADL, by directly specifying operators. 485 if(!(out.operator >>(result))) 486 return false; 487 488 return true; 489 } 490 }; 491 } 492 493 } // namespace boost 494 495 #undef BOOST_LCAST_NO_WCHAR_T 496 497 #endif // BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP 498 499