converter_lexical.hpp 19 KB

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