converter_lexical.hpp 17 KB

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