From 02e5821ab32c45fad719829e9644e5d681c9ba0b Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Thu, 15 Feb 2024 11:50:10 +0300 Subject: [PATCH] Do not use custom traits from input/output types as it leads to linktime or runtime errors (fixes #46) (#74) --- doc/lexical_cast.qbk | 7 ++- .../lexical_cast/detail/converter_lexical.hpp | 47 +------------------ .../detail/converter_lexical_streams.hpp | 24 +++++----- test/lexical_cast_test.cpp | 14 +++--- 4 files changed, 24 insertions(+), 68 deletions(-) diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk index 77711d3..6ac0f5f 100644 --- a/doc/lexical_cast.qbk +++ b/doc/lexical_cast.qbk @@ -239,10 +239,13 @@ limitation of compiler options that you use. * Significant rewrite of the internal logic to separate optimized and C++ Standard Library IO-based streams: * C++ Standard Library based streams now constructed in less cases leading to [*better performance]; - * less template instantiations and simpler maintainance; + * less template instantiations and simpler code; + * always use `std::char_traits` (do not use custom traits from input/output types as it leads to linktime or runtime errors); * support for `volatile` input types was dropped, following the C++ Standard Library trend. * Optimized conversions from std::basic_string_view and boost::basic_string_view - * Dropped dependency on Boost.NumericConversion and Boost.MPL + * Dropped dependency on Boost.NumericConversion and Boost.MPL. Fixed some cases + of converting floting point types to arithmetics. + * The library now works fine with `-fno-sanitize-recover=integer`. * [*boost 1.84.0 :] diff --git a/include/boost/lexical_cast/detail/converter_lexical.hpp b/include/boost/lexical_cast/detail/converter_lexical.hpp index 4b61549..cd9f76f 100644 --- a/include/boost/lexical_cast/detail/converter_lexical.hpp +++ b/include/boost/lexical_cast/detail/converter_lexical.hpp @@ -322,47 +322,6 @@ namespace boost { }; } - namespace detail // extract_char_traits template - { - // We are attempting to get char_traits<> from T - // template parameter. Otherwise we'll be using std::char_traits - template < class Char, class T > - struct extract_char_traits - : boost::false_type - { - typedef std::char_traits< Char > trait_t; - }; - - template < class Char, class Traits, class Alloc > - struct extract_char_traits< Char, std::basic_string< Char, Traits, Alloc > > - : boost::true_type - { - typedef Traits trait_t; - }; - - template < class Char, class Traits, class Alloc> - struct extract_char_traits< Char, boost::container::basic_string< Char, Traits, Alloc > > - : boost::true_type - { - typedef Traits trait_t; - }; - -#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW - template < class Char, class Traits > - struct extract_char_traits< Char, std::basic_string_view< Char, Traits > > - : boost::true_type - { - typedef Traits trait_t; - }; -#endif - template < class Char, class Traits > - struct extract_char_traits< Char, boost::basic_string_view< Char, Traits > > - : boost::true_type - { - typedef Traits trait_t; - }; - } - namespace detail // array_to_pointer_decay { template @@ -466,11 +425,7 @@ namespace boost { "Your compiler does not have full support for char32_t" ); #endif - typedef typename boost::conditional< - boost::detail::extract_char_traits::value, - typename boost::detail::extract_char_traits, - typename boost::detail::extract_char_traits - >::type::trait_t traits; + typedef std::char_traits traits; typedef boost::detail::lcast_src_length len_t; }; diff --git a/include/boost/lexical_cast/detail/converter_lexical_streams.hpp b/include/boost/lexical_cast/detail/converter_lexical_streams.hpp index 8dfa968..6398055 100644 --- a/include/boost/lexical_cast/detail/converter_lexical_streams.hpp +++ b/include/boost/lexical_cast/detail/converter_lexical_streams.hpp @@ -264,15 +264,15 @@ namespace boost { namespace detail { namespace lcast { ), bool >::type; - template - bool stream_in(lcast::exact> x) noexcept { + template + bool stream_in(lcast::exact> x) noexcept { start = x.payload.data(); finish = start + x.payload.length(); return true; } - template - bool stream_in(lcast::exact> x) noexcept { + template + bool stream_in(lcast::exact> x) noexcept { start = x.payload.data(); finish = start + x.payload.length(); return true; @@ -342,15 +342,15 @@ namespace boost { namespace detail { namespace lcast { } #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW - template + template enable_if_compatible_char_t - stream_in(lcast::exact> x) noexcept { + stream_in(lcast::exact> x) noexcept { return shl_char_array_limited(reinterpret_cast(x.payload.data()), x.payload.size()); } #endif - template + template enable_if_compatible_char_t - stream_in(lcast::exact> x) noexcept { + stream_in(lcast::exact> x) noexcept { return shl_char_array_limited(reinterpret_cast(x.payload.data()), x.payload.size()); } }; @@ -648,13 +648,13 @@ namespace boost { namespace detail { namespace lcast { #if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) bool stream_out(char32_t& output) { return shr_xchar(output); } #endif - template - bool stream_out(std::basic_string& str) { + template + bool stream_out(std::basic_string& str) { str.assign(start, finish); return true; } - template - bool stream_out(boost::container::basic_string& str) { + template + bool stream_out(boost::container::basic_string& str) { str.assign(start, finish); return true; } diff --git a/test/lexical_cast_test.cpp b/test/lexical_cast_test.cpp index 6d14266..ee3ecb8 100644 --- a/test/lexical_cast_test.cpp +++ b/test/lexical_cast_test.cpp @@ -390,7 +390,6 @@ void test_no_whitespace_stripping() BOOST_TEST_THROWS(lexical_cast("123 "), bad_lexical_cast); } -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION void test_traits() { typedef std::basic_string > my_string; @@ -399,6 +398,8 @@ void test_traits() BOOST_TEST(boost::lexical_cast(s) == s[0]); BOOST_TEST(boost::lexical_cast(s) == s); BOOST_TEST(boost::lexical_cast(-1) == "-1"); + BOOST_TEST(boost::lexical_cast(my_string("42")) == 42); + BOOST_TEST(boost::lexical_cast(my_string("1.0")) == 1.0); } void test_wtraits() @@ -408,9 +409,9 @@ void test_wtraits() my_string const s(L"s"); BOOST_TEST(boost::lexical_cast(s) == s[0]); BOOST_TEST(boost::lexical_cast(s) == s); - //BOOST_TEST(boost::lexical_cast(-1) == L"-1"); - // Commented out because gcc 3.3 doesn't support this: - // basic_ostream > o; o << -1; + BOOST_TEST(boost::lexical_cast(-1) == L"-1"); + BOOST_TEST(boost::lexical_cast(my_string(L"42")) == 42); + BOOST_TEST(boost::lexical_cast(my_string(L"1.0")) == 1.0); } void test_allocator() @@ -457,8 +458,6 @@ void test_wallocator() #endif } -#endif - void test_char_types_conversions() { @@ -578,12 +577,11 @@ int main() #endif test_bad_lexical_cast(); test_no_whitespace_stripping(); -#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + test_traits(); test_wtraits(); test_allocator(); test_wallocator(); -#endif test_char_types_conversions(); operators_overload_test();