converter_lexical.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. // Copyright Kevlin Henney, 2000-2005.
  2. // Copyright Alexander Nasonov, 2006-2010.
  3. // Copyright Antony Polukhin, 2011-2024.
  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/detail/lcast_precision.hpp>
  35. #include <boost/lexical_cast/detail/widest_char.hpp>
  36. #include <boost/lexical_cast/detail/is_character.hpp>
  37. #include <array>
  38. #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
  39. #include <string_view>
  40. #endif
  41. #include <boost/lexical_cast/detail/buffer_view.hpp>
  42. #include <boost/container/container_fwd.hpp>
  43. #include <boost/lexical_cast/detail/converter_lexical_streams.hpp>
  44. namespace boost {
  45. // Forward declaration
  46. template<class T, std::size_t N>
  47. class array;
  48. template<class IteratorT>
  49. class iterator_range;
  50. // Forward declaration of boost::basic_string_view from Utility
  51. template<class Ch, class Tr> class basic_string_view;
  52. namespace detail // normalize_single_byte_char<Char>
  53. {
  54. // Converts signed/unsigned char to char
  55. template < class Char >
  56. struct normalize_single_byte_char
  57. {
  58. typedef Char type;
  59. };
  60. template <>
  61. struct normalize_single_byte_char< signed char >
  62. {
  63. typedef char type;
  64. };
  65. template <>
  66. struct normalize_single_byte_char< unsigned char >
  67. {
  68. typedef char type;
  69. };
  70. }
  71. namespace detail // deduce_character_type_later<T>
  72. {
  73. // Helper type, meaning that stram character for T must be deduced
  74. // at Stage 2 (See deduce_source_char<T> and deduce_target_char<T>)
  75. template < class T > struct deduce_character_type_later {};
  76. }
  77. namespace detail // stream_char_common<T>
  78. {
  79. // Selectors to choose stream character type (common for Source and Target)
  80. // Returns one of char, wchar_t, char16_t, char32_t or deduce_character_type_later<T> types
  81. // Executed on Stage 1 (See deduce_source_char<T> and deduce_target_char<T>)
  82. template < typename Type >
  83. struct stream_char_common: public boost::conditional<
  84. boost::detail::is_character< Type >::value,
  85. Type,
  86. boost::detail::deduce_character_type_later< Type >
  87. > {};
  88. template < typename Char >
  89. struct stream_char_common< Char* >: public boost::conditional<
  90. boost::detail::is_character< Char >::value,
  91. Char,
  92. boost::detail::deduce_character_type_later< Char* >
  93. > {};
  94. template < typename Char >
  95. struct stream_char_common< const Char* >: public boost::conditional<
  96. boost::detail::is_character< Char >::value,
  97. Char,
  98. boost::detail::deduce_character_type_later< const Char* >
  99. > {};
  100. template < typename Char >
  101. struct stream_char_common< boost::conversion::detail::buffer_view< Char > >
  102. {
  103. typedef Char type;
  104. };
  105. template < typename Char >
  106. struct stream_char_common< boost::iterator_range< Char* > >: public boost::conditional<
  107. boost::detail::is_character< Char >::value,
  108. Char,
  109. boost::detail::deduce_character_type_later< boost::iterator_range< Char* > >
  110. > {};
  111. template < typename Char >
  112. struct stream_char_common< boost::iterator_range< const Char* > >: public boost::conditional<
  113. boost::detail::is_character< Char >::value,
  114. Char,
  115. boost::detail::deduce_character_type_later< boost::iterator_range< const Char* > >
  116. > {};
  117. template < class Char, class Traits, class Alloc >
  118. struct stream_char_common< std::basic_string< Char, Traits, Alloc > >
  119. {
  120. typedef Char type;
  121. };
  122. template < class Char, class Traits, class Alloc >
  123. struct stream_char_common< boost::container::basic_string< Char, Traits, Alloc > >
  124. {
  125. typedef Char type;
  126. };
  127. template < typename Char, std::size_t N >
  128. struct stream_char_common< boost::array< Char, N > >: public boost::conditional<
  129. boost::detail::is_character< Char >::value,
  130. Char,
  131. boost::detail::deduce_character_type_later< boost::array< Char, N > >
  132. > {};
  133. template < typename Char, std::size_t N >
  134. struct stream_char_common< boost::array< const Char, N > >: public boost::conditional<
  135. boost::detail::is_character< Char >::value,
  136. Char,
  137. boost::detail::deduce_character_type_later< boost::array< const Char, N > >
  138. > {};
  139. #ifndef BOOST_NO_CXX11_HDR_ARRAY
  140. template < typename Char, std::size_t N >
  141. struct stream_char_common< std::array<Char, N > >: public boost::conditional<
  142. boost::detail::is_character< Char >::value,
  143. Char,
  144. boost::detail::deduce_character_type_later< std::array< Char, N > >
  145. > {};
  146. template < typename Char, std::size_t N >
  147. struct stream_char_common< std::array< const Char, N > >: public boost::conditional<
  148. boost::detail::is_character< Char >::value,
  149. Char,
  150. boost::detail::deduce_character_type_later< std::array< const Char, N > >
  151. > {};
  152. #endif
  153. #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
  154. template < class Char, class Traits >
  155. struct stream_char_common< std::basic_string_view< Char, Traits > >
  156. {
  157. typedef Char type;
  158. };
  159. #endif
  160. template < class Char, class Traits >
  161. struct stream_char_common< boost::basic_string_view< Char, Traits > >
  162. {
  163. typedef Char type;
  164. };
  165. #ifdef BOOST_HAS_INT128
  166. template <> struct stream_char_common< boost::int128_type >: public boost::type_identity< char > {};
  167. template <> struct stream_char_common< boost::uint128_type >: public boost::type_identity< char > {};
  168. #endif
  169. #if !defined(BOOST_LCAST_NO_WCHAR_T) && defined(BOOST_NO_INTRINSIC_WCHAR_T)
  170. template <>
  171. struct stream_char_common< wchar_t >
  172. {
  173. typedef char type;
  174. };
  175. #endif
  176. }
  177. namespace detail // deduce_source_char_impl<T>
  178. {
  179. // If type T is `deduce_character_type_later` type, then tries to deduce
  180. // character type using streaming metafunctions.
  181. // Otherwise supplied type T is a character type, that must be normalized
  182. // using normalize_single_byte_char<Char>.
  183. // Executed at Stage 2 (See deduce_source_char<T> and deduce_target_char<T>)
  184. template < class Char >
  185. struct deduce_source_char_impl
  186. {
  187. typedef typename boost::detail::normalize_single_byte_char< Char >::type type;
  188. };
  189. template < class T >
  190. struct deduce_source_char_impl< deduce_character_type_later< T > >
  191. {
  192. template <class U>
  193. static auto left_shift_type(long)
  194. -> decltype( std::declval<std::basic_ostream< char >&>() << std::declval<const U&>(), char{});
  195. #if !defined(BOOST_LCAST_NO_WCHAR_T)
  196. template <class U>
  197. static auto left_shift_type(int)
  198. -> decltype( std::declval<std::basic_ostream< wchar_t >&>() << std::declval<const U&>(), wchar_t{});
  199. #endif
  200. template <class U>
  201. static void left_shift_type(...);
  202. using type = decltype(left_shift_type<T>(1L));
  203. static_assert(!std::is_same<type, void>::value,
  204. #if defined(BOOST_LCAST_NO_WCHAR_T)
  205. "Source type is not std::ostream`able and std::wostream`s are "
  206. "not supported by your STL implementation"
  207. #else
  208. "Source type is neither std::ostream`able nor std::wostream`able"
  209. #endif
  210. );
  211. };
  212. }
  213. namespace detail // deduce_target_char_impl<T>
  214. {
  215. // If type T is `deduce_character_type_later` type, then tries to deduce
  216. // character type using boost::has_right_shift<T> metafunction.
  217. // Otherwise supplied type T is a character type, that must be normalized
  218. // using normalize_single_byte_char<Char>.
  219. // Executed at Stage 2 (See deduce_source_char<T> and deduce_target_char<T>)
  220. template < class Char >
  221. struct deduce_target_char_impl
  222. {
  223. typedef typename normalize_single_byte_char< Char >::type type;
  224. };
  225. template < class T >
  226. struct deduce_target_char_impl< deduce_character_type_later<T> >
  227. {
  228. template <class U>
  229. static auto right_shift_type(long)
  230. -> decltype( std::declval<std::basic_istream< char >&>() >> std::declval<U&>(), char{});
  231. #if !defined(BOOST_LCAST_NO_WCHAR_T)
  232. template <class U>
  233. static auto right_shift_type(int)
  234. -> decltype( std::declval<std::basic_istream< wchar_t >&>() >> std::declval<U&>(), wchar_t{});
  235. #endif
  236. template <class U>
  237. static void right_shift_type(...);
  238. using type = decltype(right_shift_type<T>(1L));
  239. static_assert(!std::is_same<type, void>::value,
  240. #if defined(BOOST_LCAST_NO_WCHAR_T)
  241. "Target type is not std::istream`able and std::wistream`s are "
  242. "not supported by your STL implementation"
  243. #else
  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. template < class T >
  266. struct deduce_target_char
  267. {
  268. typedef typename stream_char_common< T >::type stage1_type;
  269. typedef typename deduce_target_char_impl< stage1_type >::type type;
  270. };
  271. template < class T >
  272. struct deduce_source_char
  273. {
  274. typedef typename stream_char_common< T >::type stage1_type;
  275. typedef typename deduce_source_char_impl< stage1_type >::type type;
  276. };
  277. }
  278. namespace detail // array_to_pointer_decay<T>
  279. {
  280. template<class T>
  281. struct array_to_pointer_decay
  282. {
  283. typedef T type;
  284. };
  285. template<class T, std::size_t N>
  286. struct array_to_pointer_decay<T[N]>
  287. {
  288. typedef const T * type;
  289. };
  290. }
  291. namespace detail // lcast_src_length
  292. {
  293. // Return max. length of string representation of Source;
  294. template< class Source, // Source type of lexical_cast.
  295. class Enable = void // helper type
  296. >
  297. struct lcast_src_length
  298. {
  299. BOOST_STATIC_CONSTANT(std::size_t, value = 1);
  300. };
  301. // Helper for integral types.
  302. // Notes on length calculation:
  303. // Max length for 32bit int with grouping "\1" and thousands_sep ',':
  304. // "-2,1,4,7,4,8,3,6,4,7"
  305. // ^ - is_signed
  306. // ^ - 1 digit not counted by digits10
  307. // ^^^^^^^^^^^^^^^^^^ - digits10 * 2
  308. //
  309. // Constant is_specialized is used instead of constant 1
  310. // to prevent buffer overflow in a rare case when
  311. // <boost/limits.hpp> doesn't add missing specialization for
  312. // numeric_limits<T> for some integral type T.
  313. // When is_specialized is false, the whole expression is 0.
  314. template <class Source>
  315. struct lcast_src_length<
  316. Source, typename boost::enable_if<boost::is_integral<Source> >::type
  317. >
  318. {
  319. BOOST_STATIC_CONSTANT(std::size_t, value =
  320. std::numeric_limits<Source>::is_signed +
  321. std::numeric_limits<Source>::is_specialized + /* == 1 */
  322. std::numeric_limits<Source>::digits10 * 2
  323. );
  324. };
  325. // Helper for floating point types.
  326. // -1.23456789e-123456
  327. // ^ sign
  328. // ^ leading digit
  329. // ^ decimal point
  330. // ^^^^^^^^ lcast_precision<Source>::value
  331. // ^ "e"
  332. // ^ exponent sign
  333. // ^^^^^^ exponent (assumed 6 or less digits)
  334. // sign + leading digit + decimal point + "e" + exponent sign == 5
  335. template<class Source>
  336. struct lcast_src_length<
  337. Source, typename boost::enable_if<boost::is_float<Source> >::type
  338. >
  339. {
  340. static_assert(
  341. std::numeric_limits<Source>::max_exponent10 <= 999999L &&
  342. std::numeric_limits<Source>::min_exponent10 >= -999999L
  343. , "");
  344. BOOST_STATIC_CONSTANT(std::size_t, value =
  345. 5 + lcast_precision<Source>::value + 6
  346. );
  347. };
  348. }
  349. namespace detail // lexical_cast_stream_traits<Source, Target>
  350. {
  351. template <class Source, class Target>
  352. struct lexical_cast_stream_traits {
  353. typedef typename boost::detail::array_to_pointer_decay<Source>::type src;
  354. typedef typename boost::remove_cv<src>::type no_cv_src;
  355. typedef boost::detail::deduce_source_char<no_cv_src> deduce_src_char_metafunc;
  356. typedef typename deduce_src_char_metafunc::type src_char_t;
  357. typedef typename boost::detail::deduce_target_char<Target>::type target_char_t;
  358. typedef typename boost::detail::widest_char<
  359. target_char_t, src_char_t
  360. >::type char_type;
  361. #if !defined(BOOST_NO_CXX11_CHAR16_T) && defined(BOOST_NO_CXX11_UNICODE_LITERALS)
  362. static_assert(!boost::is_same<char16_t, src_char_t>::value
  363. && !boost::is_same<char16_t, target_char_t>::value,
  364. "Your compiler does not have full support for char16_t" );
  365. #endif
  366. #if !defined(BOOST_NO_CXX11_CHAR32_T) && defined(BOOST_NO_CXX11_UNICODE_LITERALS)
  367. static_assert(!boost::is_same<char32_t, src_char_t>::value
  368. && !boost::is_same<char32_t, target_char_t>::value,
  369. "Your compiler does not have full support for char32_t" );
  370. #endif
  371. typedef std::char_traits<char_type> traits;
  372. typedef boost::detail::lcast_src_length<no_cv_src> len_t;
  373. };
  374. }
  375. namespace detail
  376. {
  377. template<typename Target, typename Source>
  378. struct lexical_converter_impl
  379. {
  380. typedef lexical_cast_stream_traits<Source, Target> stream_trait;
  381. typedef detail::lcast::optimized_src_stream<
  382. typename stream_trait::char_type,
  383. typename stream_trait::traits,
  384. stream_trait::len_t::value + 1
  385. > optimized_src_stream;
  386. template <class T>
  387. static auto detect_type(int)
  388. -> decltype(std::declval<optimized_src_stream&>().stream_in(std::declval<lcast::exact<T>>()), optimized_src_stream{});
  389. template <class T>
  390. static lcast::ios_src_stream<typename stream_trait::char_type, typename stream_trait::traits> detect_type(...);
  391. using from_src_stream = decltype(detect_type<Source>(1));
  392. typedef detail::lcast::to_target_stream<
  393. typename stream_trait::char_type,
  394. typename stream_trait::traits
  395. > to_target_stream;
  396. static inline bool try_convert(const Source& arg, Target& result) {
  397. from_src_stream src_stream;
  398. if (!src_stream.stream_in(lcast::exact<Source>{arg}))
  399. return false;
  400. to_target_stream out(src_stream.cbegin(), src_stream.cend());
  401. if (!out.stream_out(result))
  402. return false;
  403. return true;
  404. }
  405. };
  406. }
  407. } // namespace boost
  408. #undef BOOST_LCAST_NO_WCHAR_T
  409. #endif // BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP