try_lexical_convert.hpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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. #ifndef BOOST_LEXICAL_CAST_TRY_LEXICAL_CONVERT_HPP
  18. #define BOOST_LEXICAL_CAST_TRY_LEXICAL_CONVERT_HPP
  19. #include <boost/config.hpp>
  20. #ifdef BOOST_HAS_PRAGMA_ONCE
  21. # pragma once
  22. #endif
  23. #if defined(__clang__) || (defined(__GNUC__) && \
  24. !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) && \
  25. (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
  26. #pragma GCC diagnostic push
  27. #pragma GCC diagnostic ignored "-Wuninitialized"
  28. #pragma GCC diagnostic ignored "-Wsign-conversion"
  29. #endif
  30. #include <string>
  31. #include <boost/type_traits/is_integral.hpp>
  32. #include <boost/type_traits/type_identity.hpp>
  33. #include <boost/type_traits/conditional.hpp>
  34. #include <boost/type_traits/is_same.hpp>
  35. #include <boost/type_traits/is_arithmetic.hpp>
  36. #include <boost/lexical_cast/detail/is_character.hpp>
  37. #include <boost/lexical_cast/detail/converter_numeric.hpp>
  38. #include <boost/lexical_cast/detail/converter_lexical.hpp>
  39. #include <boost/range/iterator_range_core.hpp>
  40. #include <boost/container/container_fwd.hpp>
  41. namespace boost {
  42. namespace detail
  43. {
  44. template<typename T>
  45. struct is_stdstring
  46. : boost::false_type
  47. {};
  48. template<typename CharT, typename Traits, typename Alloc>
  49. struct is_stdstring< std::basic_string<CharT, Traits, Alloc> >
  50. : boost::true_type
  51. {};
  52. // Sun Studio has problem with partial specialization of templates differing only in namespace.
  53. // We workaround that by making `is_booststring` trait, instead of specializing `is_stdstring` for `boost::container::basic_string`.
  54. template<typename T>
  55. struct is_booststring
  56. : boost::false_type
  57. {};
  58. template<typename CharT, typename Traits, typename Alloc>
  59. struct is_booststring< boost::container::basic_string<CharT, Traits, Alloc> >
  60. : boost::true_type
  61. {};
  62. template<typename Target, typename Source>
  63. struct is_arithmetic_and_not_xchars
  64. {
  65. typedef boost::integral_constant<
  66. bool,
  67. !(boost::detail::is_character<Target>::value) &&
  68. !(boost::detail::is_character<Source>::value) &&
  69. boost::is_arithmetic<Source>::value &&
  70. boost::is_arithmetic<Target>::value
  71. > type;
  72. BOOST_STATIC_CONSTANT(bool, value = (
  73. type::value
  74. ));
  75. };
  76. /*
  77. * is_xchar_to_xchar<Target, Source>::value is true,
  78. * Target and Souce are char types of the same size 1 (char, signed char, unsigned char).
  79. */
  80. template<typename Target, typename Source>
  81. struct is_xchar_to_xchar
  82. {
  83. typedef boost::integral_constant<
  84. bool,
  85. sizeof(Source) == sizeof(Target) &&
  86. sizeof(Source) == sizeof(char) &&
  87. boost::detail::is_character<Target>::value &&
  88. boost::detail::is_character<Source>::value
  89. > type;
  90. BOOST_STATIC_CONSTANT(bool, value = (
  91. type::value
  92. ));
  93. };
  94. template<typename Target, typename Source>
  95. struct is_char_array_to_stdstring
  96. : boost::false_type
  97. {};
  98. template<typename CharT, typename Traits, typename Alloc>
  99. struct is_char_array_to_stdstring< std::basic_string<CharT, Traits, Alloc>, CharT* >
  100. : boost::true_type
  101. {};
  102. template<typename CharT, typename Traits, typename Alloc>
  103. struct is_char_array_to_stdstring< std::basic_string<CharT, Traits, Alloc>, const CharT* >
  104. : boost::true_type
  105. {};
  106. // Sun Studio has problem with partial specialization of templates differing only in namespace.
  107. // We workaround that by making `is_char_array_to_booststring` trait, instead of specializing `is_char_array_to_stdstring` for `boost::container::basic_string`.
  108. template<typename Target, typename Source>
  109. struct is_char_array_to_booststring
  110. : boost::false_type
  111. {};
  112. template<typename CharT, typename Traits, typename Alloc>
  113. struct is_char_array_to_booststring< boost::container::basic_string<CharT, Traits, Alloc>, CharT* >
  114. : boost::true_type
  115. {};
  116. template<typename CharT, typename Traits, typename Alloc>
  117. struct is_char_array_to_booststring< boost::container::basic_string<CharT, Traits, Alloc>, const CharT* >
  118. : boost::true_type
  119. {};
  120. template <typename Target, typename Source>
  121. struct copy_converter_impl
  122. {
  123. // MSVC fail to forward an array (DevDiv#555157 "SILENT BAD CODEGEN triggered by perfect forwarding",
  124. // fixed in 2013 RTM).
  125. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && (!defined(BOOST_MSVC) || BOOST_MSVC >= 1800)
  126. template <class T>
  127. static inline bool try_convert(T&& arg, Target& result) {
  128. result = static_cast<T&&>(arg); // eqaul to `result = std::forward<T>(arg);`
  129. return true;
  130. }
  131. #else
  132. static inline bool try_convert(const Source& arg, Target& result) {
  133. result = arg;
  134. return true;
  135. }
  136. #endif
  137. };
  138. }
  139. namespace conversion { namespace detail {
  140. template <typename Target, typename Source>
  141. inline bool try_lexical_convert(const Source& arg, Target& result)
  142. {
  143. typedef BOOST_DEDUCED_TYPENAME boost::detail::array_to_pointer_decay<Source>::type src;
  144. typedef boost::integral_constant<
  145. bool,
  146. boost::detail::is_xchar_to_xchar<Target, src >::value ||
  147. boost::detail::is_char_array_to_stdstring<Target, src >::value ||
  148. boost::detail::is_char_array_to_booststring<Target, src >::value ||
  149. (
  150. boost::is_same<Target, src >::value &&
  151. (boost::detail::is_stdstring<Target >::value || boost::detail::is_booststring<Target >::value)
  152. ) ||
  153. (
  154. boost::is_same<Target, src >::value &&
  155. boost::detail::is_character<Target >::value
  156. )
  157. > shall_we_copy_t;
  158. typedef boost::detail::is_arithmetic_and_not_xchars<Target, src >
  159. shall_we_copy_with_dynamic_check_t;
  160. // We do evaluate second `if_` lazily to avoid unnecessary instantiations
  161. // of `shall_we_copy_with_dynamic_check_t` and improve compilation times.
  162. typedef BOOST_DEDUCED_TYPENAME boost::conditional<
  163. shall_we_copy_t::value,
  164. boost::type_identity<boost::detail::copy_converter_impl<Target, src > >,
  165. boost::conditional<
  166. shall_we_copy_with_dynamic_check_t::value,
  167. boost::detail::dynamic_num_converter_impl<Target, src >,
  168. boost::detail::lexical_converter_impl<Target, src >
  169. >
  170. >::type caster_type_lazy;
  171. typedef BOOST_DEDUCED_TYPENAME caster_type_lazy::type caster_type;
  172. return caster_type::try_convert(arg, result);
  173. }
  174. template <typename Target, typename CharacterT>
  175. inline bool try_lexical_convert(const CharacterT* chars, std::size_t count, Target& result)
  176. {
  177. BOOST_STATIC_ASSERT_MSG(
  178. boost::detail::is_character<CharacterT>::value,
  179. "This overload of try_lexical_convert is meant to be used only with arrays of characters."
  180. );
  181. return ::boost::conversion::detail::try_lexical_convert(
  182. ::boost::iterator_range<const CharacterT*>(chars, chars + count), result
  183. );
  184. }
  185. }} // namespace conversion::detail
  186. namespace conversion {
  187. // ADL barrier
  188. using ::boost::conversion::detail::try_lexical_convert;
  189. }
  190. } // namespace boost
  191. #if defined(__clang__) || (defined(__GNUC__) && \
  192. !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) && \
  193. (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
  194. #pragma GCC diagnostic pop
  195. #endif
  196. #endif // BOOST_LEXICAL_CAST_TRY_LEXICAL_CONVERT_HPP