try_lexical_convert.hpp 8.8 KB

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