Browse Source

Revert boost/lexical_cast to pre-PR#70 version to fix tests

This PR has broken the tests:
https://github.com/boostorg/lexical_cast/pull/70

as can be seen here:
https://a.yandex-team.ru/arcadia/commit/rXXXXXX/checks
8c9b2a7490283d0744d97fc6213a503d27fc7e73
thegeorg 8 months ago
parent
commit
aa7cbf9b8c

+ 32 - 22
contrib/restricted/boost/lexical_cast/include/boost/lexical_cast/detail/converter_lexical.hpp

@@ -42,10 +42,6 @@
 
 #include <array>
 
-#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
-#include <string_view>
-#endif
-
 #include <boost/lexical_cast/detail/buffer_view.hpp>
 #include <boost/container/container_fwd.hpp>
 
@@ -59,9 +55,6 @@ namespace boost {
     template<class IteratorT>
     class iterator_range;
 
-    // Forward declaration of boost::basic_string_view from Utility
-    template<class Ch, class Tr> class basic_string_view;
-
     namespace detail // normalize_single_byte_char<Char>
     {
         // Converts signed/unsigned char to char
@@ -179,19 +172,6 @@ namespace boost {
         > {};
 #endif
 
-#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
-        template < class Char, class Traits >
-        struct stream_char_common< std::basic_string_view< Char, Traits > >
-        {
-            typedef Char type;
-        };
-#endif
-        template < class Char, class Traits >
-        struct stream_char_common< boost::basic_string_view< Char, Traits > >
-        {
-            typedef Char type;
-        };
-
 #ifdef BOOST_HAS_INT128
         template <> struct stream_char_common< boost::int128_type >: public boost::type_identity< char > {};
         template <> struct stream_char_common< boost::uint128_type >: public boost::type_identity< char > {};
@@ -322,6 +302,32 @@ 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<Char>
+        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;
+        };
+    }
+
     namespace detail // array_to_pointer_decay<T>
     {
         template<class T>
@@ -425,7 +431,11 @@ namespace boost {
                 "Your compiler does not have full support for char32_t" );
 #endif
 
-            typedef std::char_traits<char_type> traits;
+            typedef typename boost::conditional<
+                boost::detail::extract_char_traits<char_type, Target>::value,
+                typename boost::detail::extract_char_traits<char_type, Target>,
+                typename boost::detail::extract_char_traits<char_type, no_cv_src>
+            >::type::trait_t traits;
 
             typedef boost::detail::lcast_src_length<no_cv_src> len_t;
         };
@@ -464,7 +474,7 @@ namespace boost {
                     return false;
 
                 to_target_stream out(src_stream.cbegin(), src_stream.cend());
-                if (!out.stream_out(result))
+                if(!(out.stream_out(result)))
                     return false;
 
                 return true;

+ 37 - 60
contrib/restricted/boost/lexical_cast/include/boost/lexical_cast/detail/converter_lexical_streams.hpp

@@ -77,6 +77,7 @@
 #include <boost/type_traits/is_const.hpp>
 #include <boost/type_traits/is_reference.hpp>
 #include <boost/container/container_fwd.hpp>
+#include <boost/core/noncopyable.hpp>
 #include <boost/core/enable_if.hpp>
 #ifndef BOOST_NO_CWCHAR
 #   include <cwchar>
@@ -88,9 +89,6 @@ namespace boost {
     class array;
     template<class IteratorT>
     class iterator_range;
-
-    // forward declaration of boost::basic_string_view from Utility
-    template<class Ch, class Tr> class basic_string_view;
 }
 
 namespace boost { namespace detail { namespace lcast {
@@ -107,7 +105,7 @@ namespace boost { namespace detail { namespace lcast {
             , class Traits
             , std::size_t CharacterBufferSize
             >
-    class optimized_src_stream {
+    class optimized_src_stream: boost::noncopyable {
         CharT buffer[CharacterBufferSize];
 
         // After the `stream_in(`  finishes, `[start, finish)` is
@@ -115,11 +113,6 @@ namespace boost { namespace detail { namespace lcast {
         const CharT*  start;
         const CharT*  finish;
     public:
-        optimized_src_stream(optimized_src_stream&&) = delete;
-        optimized_src_stream(const optimized_src_stream&) = delete;
-        optimized_src_stream& operator=(optimized_src_stream&&) = delete;
-        optimized_src_stream& operator=(const optimized_src_stream&) = delete;
-
         optimized_src_stream() noexcept
           : start(buffer)
           , finish(buffer + CharacterBufferSize)
@@ -254,25 +247,15 @@ namespace boost { namespace detail { namespace lcast {
         }
 #endif
     public:
-        template <class C>
-        using enable_if_compatible_char_t = typename boost::enable_if_c<
-            boost::is_same<const C, const CharT>::value || (
-                boost::is_same<const char, const CharT>::value && (
-                    boost::is_same<const C, const unsigned char>::value ||
-                    boost::is_same<const C, const signed char>::value
-                )
-            ), bool
-        >::type;
-
-        template<class CharTraits, class Alloc>
-        bool stream_in(lcast::exact<std::basic_string<CharT,CharTraits,Alloc>> x) noexcept {
+        template<class Alloc>
+        bool stream_in(lcast::exact<std::basic_string<CharT,Traits,Alloc>> x) noexcept {
             start = x.payload.data();
             finish = start + x.payload.length();
             return true;
         }
 
-        template<class CharTraits, class Alloc>
-        bool stream_in(lcast::exact<boost::container::basic_string<CharT,CharTraits,Alloc>> x) noexcept {
+        template<class Alloc>
+        bool stream_in(lcast::exact<boost::container::basic_string<CharT,Traits,Alloc>> x) noexcept {
             start = x.payload.data();
             finish = start + x.payload.length();
             return true;
@@ -292,12 +275,19 @@ namespace boost { namespace detail { namespace lcast {
         }
 
         template <class C>
-        enable_if_compatible_char_t<C>
+        typename boost::enable_if_c<boost::detail::is_character<C>::value && sizeof(CharT) == sizeof(C), bool>::type
         stream_in(lcast::exact<boost::iterator_range<C*>> x) noexcept {
             auto buf = boost::conversion::detail::make_buffer_view(x.payload.begin(), x.payload.end());
             return stream_in(lcast::exact<decltype(buf)>{buf});
         }
 
+        template <class C>
+        typename boost::enable_if_c<boost::detail::is_character<C>::value && sizeof(CharT) == sizeof(C), bool>::type
+        stream_in(lcast::exact<boost::iterator_range<const C*>> x) noexcept {
+            auto buf = boost::conversion::detail::make_buffer_view(x.payload.begin(), x.payload.end());
+            return stream_in(lcast::exact<decltype(buf)>{buf});
+        }
+
         bool stream_in(lcast::exact<char> x)                    { return shl_char(x.payload); }
         bool stream_in(lcast::exact<unsigned char> x)           { return shl_char(static_cast<char>(x.payload)); }
         bool stream_in(lcast::exact<signed char> x)             { return shl_char(static_cast<char>(x.payload)); }
@@ -307,8 +297,12 @@ namespace boost { namespace detail { namespace lcast {
                 stream_in(lcast::exact<C> x)                    { return shl_char(x.payload); }
 
         template <class Type>
-        enable_if_compatible_char_t<Type>
-                stream_in(lcast::exact<Type*> x)                { return shl_char_array(reinterpret_cast<CharT const*>(x.payload)); }
+        typename boost::enable_if_c<boost::detail::is_character<Type>::value && sizeof(CharT) == sizeof(Type), bool>::type
+                stream_in(lcast::exact<const Type*> x)          { return shl_char_array(reinterpret_cast<CharT const*>(x.payload)); }
+
+        template <class Type>
+        typename boost::enable_if_c<boost::detail::is_character<Type>::value && sizeof(CharT) == sizeof(Type), bool>::type
+                stream_in(lcast::exact<Type*> x)                { return shl_char_array(reinterpret_cast<CharT*>(x.payload)); }
 
         template <class Type>
         typename boost::enable_if_c<boost::is_signed<Type>::value && !boost::is_enum<Type>::value, bool>::type
@@ -330,28 +324,27 @@ namespace boost { namespace detail { namespace lcast {
         }
 
         template <class C, std::size_t N>
-        enable_if_compatible_char_t<C>
+        typename boost::enable_if_c<boost::detail::is_character<C>::value && sizeof(CharT) == sizeof(C), bool>::type
         stream_in(lcast::exact<boost::array<C, N>> x) noexcept {
             return shl_char_array_limited(reinterpret_cast<const CharT*>(x.payload.data()), N);
         }
 
         template <class C, std::size_t N>
-        enable_if_compatible_char_t<C>
-        stream_in(lcast::exact<std::array<C, N>> x) noexcept {
+        typename boost::enable_if_c<boost::detail::is_character<C>::value && sizeof(CharT) == sizeof(C), bool>::type
+        stream_in(lcast::exact<boost::array<const C, N>> x) noexcept {
             return shl_char_array_limited(reinterpret_cast<const CharT*>(x.payload.data()), N);
         }
 
-#ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
-        template <class C, class CharTraits>
-        enable_if_compatible_char_t<C>
-        stream_in(lcast::exact<std::basic_string_view<C, CharTraits>> x) noexcept {
-            return shl_char_array_limited(reinterpret_cast<const CharT*>(x.payload.data()), x.payload.size());
+        template <class C, std::size_t N>
+        typename boost::enable_if_c<boost::detail::is_character<C>::value && sizeof(CharT) == sizeof(C), bool>::type
+        stream_in(lcast::exact<std::array<C, N>> x) noexcept {
+            return shl_char_array_limited(reinterpret_cast<const CharT*>(x.payload.data()), N);
         }
-#endif
-        template <class C, class CharTraits>
-        enable_if_compatible_char_t<C>
-        stream_in(lcast::exact<boost::basic_string_view<C, CharTraits>> x) noexcept {
-            return shl_char_array_limited(reinterpret_cast<const CharT*>(x.payload.data()), x.payload.size());
+
+        template <class C, std::size_t N>
+        typename boost::enable_if_c<boost::detail::is_character<C>::value && sizeof(CharT) == sizeof(C), bool>::type
+        stream_in(lcast::exact<std::array<const C, N>> x) noexcept {
+            return shl_char_array_limited(reinterpret_cast<const CharT*>(x.payload.data()), N);
         }
     };
 
@@ -367,11 +360,6 @@ namespace boost { namespace detail { namespace lcast {
         const CharT*  start = nullptr;
         const CharT*  finish = nullptr;
     public:
-        ios_src_stream(ios_src_stream&&) = delete;
-        ios_src_stream(const ios_src_stream&) = delete;
-        ios_src_stream& operator=(ios_src_stream&&) = delete;
-        ios_src_stream& operator=(const ios_src_stream&) = delete;
-
         ios_src_stream(): out_buffer(), out_stream(&out_buffer) {}
 
         const CharT* cbegin() const noexcept {
@@ -472,17 +460,12 @@ namespace boost { namespace detail { namespace lcast {
 
 
     template <class CharT, class Traits>
-    class to_target_stream {
+    class to_target_stream: boost::noncopyable {
         //`[start, finish)` is the range to output by `operator >>`
         const CharT*        start;
         const CharT* const  finish;
 
     public:
-        to_target_stream(to_target_stream&&) = delete;
-        to_target_stream(const to_target_stream&) = delete;
-        to_target_stream& operator=(to_target_stream&&) = delete;
-        to_target_stream& operator=(const to_target_stream&) = delete;
-
         to_target_stream(const CharT* begin, const CharT* end) noexcept
           : start(begin)
           , finish(end)
@@ -490,9 +473,6 @@ namespace boost { namespace detail { namespace lcast {
 
     private:
         template <typename Type>
-#if defined(__clang__) && (__clang_major__ > 3 || __clang_minor__ > 6)
-        __attribute__((no_sanitize("unsigned-integer-overflow")))
-#endif
         bool shr_unsigned(Type& output) {
             if (start == finish) return false;
             CharT const minus = lcast_char_constants<CharT>::minus;
@@ -514,9 +494,6 @@ namespace boost { namespace detail { namespace lcast {
         }
 
         template <typename Type>
-#if defined(__clang__) && (__clang_major__ > 3 || __clang_minor__ > 6)
-        __attribute__((no_sanitize("unsigned-integer-overflow")))
-#endif
         bool shr_signed(Type& output) {
             if (start == finish) return false;
             CharT const minus = lcast_char_constants<CharT>::minus;
@@ -648,13 +625,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<class CharTraits, class Alloc>
-        bool stream_out(std::basic_string<CharT,CharTraits,Alloc>& str) {
+        template<class Alloc>
+        bool stream_out(std::basic_string<CharT,Traits,Alloc>& str) {
             str.assign(start, finish); return true;
         }
 
-        template<class CharTraits, class Alloc>
-        bool stream_out(boost::container::basic_string<CharT,CharTraits,Alloc>& str) {
+        template<class Alloc>
+        bool stream_out(boost::container::basic_string<CharT,Traits,Alloc>& str) {
             str.assign(start, finish); return true;
         }
 

+ 75 - 81
contrib/restricted/boost/lexical_cast/include/boost/lexical_cast/detail/converter_numeric.hpp

@@ -23,107 +23,101 @@
 #   pragma once
 #endif
 
-#include <boost/core/cmath.hpp>
-#include <boost/core/enable_if.hpp>
 #include <boost/limits.hpp>
 #include <boost/type_traits/type_identity.hpp>
 #include <boost/type_traits/conditional.hpp>
 #include <boost/type_traits/make_unsigned.hpp>
 #include <boost/type_traits/is_signed.hpp>
+#include <boost/type_traits/is_integral.hpp>
 #include <boost/type_traits/is_arithmetic.hpp>
+#include <boost/type_traits/is_base_of.hpp>
 #include <boost/type_traits/is_float.hpp>
+#include <boost/type_traits/remove_volatile.hpp>
 
-namespace boost { namespace detail {
-
-template <class Source, class Target>
-bool ios_numeric_comparer_float(Source x, Source y) noexcept {
-    return x == y
-        || (boost::core::isnan(x) && boost::core::isnan(y))
-        || (x < (std::numeric_limits<Target>::min)())
-    ;
-}
+#include <boost/numeric/conversion/cast.hpp>
 
-template <class RangeType, class T>
-constexpr bool is_out_of_range_for(T value) noexcept {
-    return value > static_cast<T>((std::numeric_limits<RangeType>::max)())
-        || value < static_cast<T>((std::numeric_limits<RangeType>::min)());
-}
+namespace boost { namespace detail {
 
+template <class Source >
+struct detect_precision_loss
+{
+    typedef Source source_type;
+    typedef boost::numeric::Trunc<Source> Rounder;
+    typedef typename conditional<
+        boost::is_arithmetic<Source>::value, Source, Source const&
+    >::type argument_type ;
+
+    static inline source_type nearbyint(argument_type s, bool& is_ok) noexcept {
+        const source_type near_int = Rounder::nearbyint(s);
+        if (near_int && is_ok) {
+            const source_type orig_div_round = s / near_int;
+            const source_type eps = std::numeric_limits<source_type>::epsilon();
+
+            is_ok = !((orig_div_round > 1 ? orig_div_round - 1 : 1 - orig_div_round) > eps);
+        }
 
-// integral -> integral
-template <typename Target, typename Source>
-typename boost::enable_if_c<
-    !boost::is_floating_point<Source>::value && !boost::is_floating_point<Target>::value, bool
->::type noexcept_numeric_convert(Source arg, Target& result) noexcept {
-    const Target target_tmp = static_cast<Target>(arg);
-    const Source arg_restored = static_cast<Source>(target_tmp);
-    if (arg == arg_restored) {
-        result = target_tmp;
-        return true;
+        return s;
     }
-    return false;
-}
 
-// integral -> floating point
-template <typename Target, typename Source>
-typename boost::enable_if_c<
-    !boost::is_floating_point<Source>::value && boost::is_floating_point<Target>::value, bool
->::type noexcept_numeric_convert(Source arg, Target& result) noexcept {
-    const Target target_tmp = static_cast<Target>(arg);
-    result = target_tmp;
-    return true;
-}
+    typedef typename Rounder::round_style round_style;
+};
 
+template <typename Base, class Source>
+struct fake_precision_loss: public Base
+{
+    typedef Source source_type ;
+    typedef typename conditional<
+        boost::is_arithmetic<Source>::value, Source, Source const&
+    >::type argument_type ;
 
-// floating point -> floating point
-template <typename Target, typename Source>
-typename boost::enable_if_c<
-    boost::is_floating_point<Source>::value && boost::is_floating_point<Target>::value, bool
->::type noexcept_numeric_convert(Source arg, Target& result) noexcept {
-    const Target target_tmp = static_cast<Target>(arg);
-    const Source arg_restored = static_cast<Source>(target_tmp);
-    if (detail::ios_numeric_comparer_float<Source, Target>(arg, arg_restored)) {
-        result = target_tmp;
-        return true;
+    static inline source_type nearbyint(argument_type s, bool& /*is_ok*/) noexcept {
+        return s;
     }
+};
 
-    return false;
-}
-
-// floating point -> integral
-template <typename Target, typename Source>
-typename boost::enable_if_c<
-    boost::is_floating_point<Source>::value && !boost::is_floating_point<Target>::value, bool
->::type noexcept_numeric_convert(Source arg, Target& result) noexcept {
-    if (detail::is_out_of_range_for<Target>(arg)) {
-        return false;
+struct nothrow_overflow_handler
+{
+    inline bool operator() ( boost::numeric::range_check_result r ) const noexcept {
+        return (r == boost::numeric::cInRange);
     }
+};
 
-    const Target target_tmp = static_cast<Target>(arg);
-    const Source arg_restored = static_cast<Source>(target_tmp);
-    if (detail::ios_numeric_comparer_float<Source, Target>(arg, arg_restored)) {
-        result = target_tmp;
-        return true;
+template <typename Target, typename Source>
+inline bool noexcept_numeric_convert(const Source& arg, Target& result) noexcept {
+    typedef boost::numeric::converter<
+            Target,
+            Source,
+            boost::numeric::conversion_traits<Target, Source >,
+            nothrow_overflow_handler,
+            detect_precision_loss<Source >
+    > converter_orig_t;
+
+    typedef typename boost::conditional<
+        boost::is_base_of< detect_precision_loss<Source >, converter_orig_t >::value,
+        converter_orig_t,
+        fake_precision_loss<converter_orig_t, Source>
+    >::type converter_t;
+
+    bool res = nothrow_overflow_handler()(converter_t::out_of_range(arg));
+    if (res) {
+        result = converter_t::low_level_convert(converter_t::nearbyint(arg, res));
     }
 
-    return false;
+    return res;
 }
 
+template <typename Target, typename Source>
 struct lexical_cast_dynamic_num_not_ignoring_minus
 {
-    template <typename Target, typename Source>
-    static inline bool try_convert(Source arg, Target& result) noexcept {
-        return boost::detail::noexcept_numeric_convert<Target, Source >(arg, result);
+    static inline bool try_convert(const Source &arg, Target& result) noexcept {
+        return noexcept_numeric_convert<Target, Source >(arg, result);
     }
 };
 
+template <typename Target, typename Source>
 struct lexical_cast_dynamic_num_ignoring_minus
 {
-    template <typename Target, typename Source>
-#if defined(__clang__) && (__clang_major__ > 3 || __clang_minor__ > 6)
-    __attribute__((no_sanitize("unsigned-integer-overflow")))
-#endif
-    static inline bool try_convert(Source arg, Target& result) noexcept {
+    static inline bool try_convert(const Source &arg, Target& result) noexcept {
         typedef typename boost::conditional<
                 boost::is_float<Source>::value,
                 boost::type_identity<Source>,
@@ -132,19 +126,17 @@ struct lexical_cast_dynamic_num_ignoring_minus
         typedef typename usource_lazy_t::type usource_t;
 
         if (arg < 0) {
-            const bool res = boost::detail::noexcept_numeric_convert<Target, usource_t>(
-                static_cast<usource_t>(0u - static_cast<usource_t>(arg)), result
-            );
+            const bool res = noexcept_numeric_convert<Target, usource_t>(0u - arg, result);
             result = static_cast<Target>(0u - result);
             return res;
         } else {
-            return boost::detail::noexcept_numeric_convert<Target, usource_t>(arg, result);
+            return noexcept_numeric_convert<Target, usource_t>(arg, result);
         }
     }
 };
 
 /*
- * dynamic_num_converter_impl follows the rules:
+ * lexical_cast_dynamic_num follows the rules:
  * 1) If Source can be converted to Target without precision loss and
  * without overflows, then assign Source to Target and return
  *
@@ -164,14 +156,16 @@ struct lexical_cast_dynamic_num_ignoring_minus
 template <typename Target, typename Source>
 struct dynamic_num_converter_impl
 {
-    static inline bool try_convert(Source arg, Target& result) noexcept {
+    typedef typename boost::remove_volatile<Source>::type source_type;
+
+    static inline bool try_convert(source_type arg, Target& result) noexcept {
         typedef typename boost::conditional<
             boost::is_unsigned<Target>::value &&
-            (boost::is_signed<Source>::value || boost::is_float<Source>::value) &&
-            !(boost::is_same<Source, bool>::value) &&
+            (boost::is_signed<source_type>::value || boost::is_float<source_type>::value) &&
+            !(boost::is_same<source_type, bool>::value) &&
             !(boost::is_same<Target, bool>::value),
-            lexical_cast_dynamic_num_ignoring_minus,
-            lexical_cast_dynamic_num_not_ignoring_minus
+            lexical_cast_dynamic_num_ignoring_minus<Target, source_type>,
+            lexical_cast_dynamic_num_not_ignoring_minus<Target, source_type>
         >::type caster_type;
 
         return caster_type::try_convert(arg, result);

+ 0 - 6
contrib/restricted/boost/lexical_cast/include/boost/lexical_cast/detail/lcast_unsigned_converters.hpp

@@ -56,9 +56,6 @@ namespace boost
     namespace detail // lcast_to_unsigned
     {
         template<class T>
-#if defined(__clang__) && (__clang_major__ > 3 || __clang_minor__ > 6)
-       __attribute__((no_sanitize("unsigned-integer-overflow")))
-#endif
         inline
         typename boost::make_unsigned<T>::type lcast_to_unsigned(const T value) noexcept {
             typedef typename boost::make_unsigned<T>::type result_type;
@@ -254,9 +251,6 @@ namespace boost
         private:
             // Iteration that does not care about grouping/separators and assumes that all
             // input characters are digits
-#if defined(__clang__) && (__clang_major__ > 3 || __clang_minor__ > 6)
-            __attribute__((no_sanitize("unsigned-integer-overflow")))
-#endif
             inline bool main_convert_iteration() noexcept {
                 CharT const czero = lcast_char_constants<CharT>::zero;
                 T const maxv = (std::numeric_limits<T>::max)();

+ 134 - 4
contrib/restricted/boost/lexical_cast/include/boost/lexical_cast/try_lexical_convert.hpp

@@ -23,7 +23,20 @@
 #   pragma once
 #endif
 
+#if defined(__clang__) || (defined(__GNUC__) && \
+    !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) && \
+    (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wuninitialized"
+#pragma GCC diagnostic ignored "-Wsign-conversion"
+#endif
+
+
+#include <string>
+#include <boost/type_traits/is_integral.hpp>
+#include <boost/type_traits/type_identity.hpp>
 #include <boost/type_traits/conditional.hpp>
+#include <boost/type_traits/is_same.hpp>
 #include <boost/type_traits/is_arithmetic.hpp>
 
 #include <boost/lexical_cast/detail/buffer_view.hpp>
@@ -31,9 +44,33 @@
 #include <boost/lexical_cast/detail/converter_numeric.hpp>
 #include <boost/lexical_cast/detail/converter_lexical.hpp>
 
+#include <boost/container/container_fwd.hpp>
+
 namespace boost {
     namespace detail
     {
+        template<typename T>
+        struct is_stdstring
+            : boost::false_type
+        {};
+
+        template<typename CharT, typename Traits, typename Alloc>
+        struct is_stdstring< std::basic_string<CharT, Traits, Alloc> >
+            : boost::true_type
+        {};
+
+        // Sun Studio has problem with partial specialization of templates differing only in namespace.
+        // We workaround that by making `is_booststring` trait, instead of specializing `is_stdstring` for `boost::container::basic_string`.
+        template<typename T>
+        struct is_booststring
+            : boost::false_type
+        {};
+
+        template<typename CharT, typename Traits, typename Alloc>
+        struct is_booststring< boost::container::basic_string<CharT, Traits, Alloc> >
+            : boost::true_type
+        {};
+
         template<typename Target, typename Source>
         using is_arithmetic_and_not_xchars = boost::integral_constant<
             bool,
@@ -42,6 +79,70 @@ namespace boost {
                 boost::is_arithmetic<Source>::value &&
                 boost::is_arithmetic<Target>::value
         >;
+
+        /*
+         * is_xchar_to_xchar<Target, Source>::value is true,
+         * Target and Souce are char types of the same size 1 (char, signed char, unsigned char).
+         */
+        template<typename Target, typename Source>
+        using is_xchar_to_xchar = boost::integral_constant<
+            bool,
+            sizeof(Source) == sizeof(Target) &&
+                 sizeof(Source) == sizeof(char) &&
+                 boost::detail::is_character<Target>::value &&
+                 boost::detail::is_character<Source>::value
+        >;
+
+        template<typename Target, typename Source>
+        struct is_char_array_to_stdstring
+            : boost::false_type
+        {};
+
+        template<typename CharT, typename Traits, typename Alloc>
+        struct is_char_array_to_stdstring< std::basic_string<CharT, Traits, Alloc>, CharT* >
+            : boost::true_type
+        {};
+
+        template<typename CharT, typename Traits, typename Alloc>
+        struct is_char_array_to_stdstring< std::basic_string<CharT, Traits, Alloc>, const CharT* >
+            : boost::true_type
+        {};
+
+        // Sun Studio has problem with partial specialization of templates differing only in namespace.
+        // We workaround that by making `is_char_array_to_booststring` trait, instead of specializing `is_char_array_to_stdstring` for `boost::container::basic_string`.
+        template<typename Target, typename Source>
+        struct is_char_array_to_booststring
+            : boost::false_type
+        {};
+
+        template<typename CharT, typename Traits, typename Alloc>
+        struct is_char_array_to_booststring< boost::container::basic_string<CharT, Traits, Alloc>, CharT* >
+            : boost::true_type
+        {};
+
+        template<typename CharT, typename Traits, typename Alloc>
+        struct is_char_array_to_booststring< boost::container::basic_string<CharT, Traits, Alloc>, const CharT* >
+            : boost::true_type
+        {};
+
+        template <typename Target, typename Source>
+        struct copy_converter_impl
+        {
+// MSVC fail to forward an array (DevDiv#555157 "SILENT BAD CODEGEN triggered by perfect forwarding",
+// fixed in 2013 RTM).
+#if !defined(BOOST_MSVC) || BOOST_MSVC >= 1800
+            template <class T>
+            static inline bool try_convert(T&& arg, Target& result) {
+                result = static_cast<T&&>(arg); // eqaul to `result = std::forward<T>(arg);`
+                return true;
+            }
+#else
+            static inline bool try_convert(const Source& arg, Target& result) {
+                result = arg;
+                return true;
+            }
+#endif
+        };
     }
 
     namespace conversion { namespace detail {
@@ -55,14 +156,37 @@ namespace boost {
 
             typedef typename boost::detail::array_to_pointer_decay<Source>::type src;
 
+            typedef boost::integral_constant<
+                bool,
+                boost::detail::is_xchar_to_xchar<Target, src >::value ||
+                boost::detail::is_char_array_to_stdstring<Target, src >::value ||
+                boost::detail::is_char_array_to_booststring<Target, src >::value ||
+                (
+                     boost::is_same<Target, src >::value &&
+                     (boost::detail::is_stdstring<Target >::value || boost::detail::is_booststring<Target >::value)
+                ) ||
+                (
+                     boost::is_same<Target, src >::value &&
+                     boost::detail::is_character<Target >::value
+                )
+            > shall_we_copy_t;
+
             typedef boost::detail::is_arithmetic_and_not_xchars<Target, src >
                 shall_we_copy_with_dynamic_check_t;
 
+            // We do evaluate second `if_` lazily to avoid unnecessary instantiations
+            // of `shall_we_copy_with_dynamic_check_t` and improve compilation times.
             typedef typename boost::conditional<
-                 shall_we_copy_with_dynamic_check_t::value,
-                 boost::detail::dynamic_num_converter_impl<Target, src >,
-                 boost::detail::lexical_converter_impl<Target, src >
-            >::type caster_type;
+                shall_we_copy_t::value,
+                boost::type_identity<boost::detail::copy_converter_impl<Target, src > >,
+                boost::conditional<
+                     shall_we_copy_with_dynamic_check_t::value,
+                     boost::detail::dynamic_num_converter_impl<Target, src >,
+                     boost::detail::lexical_converter_impl<Target, src >
+                >
+            >::type caster_type_lazy;
+
+            typedef typename caster_type_lazy::type caster_type;
 
             return caster_type::try_convert(arg, result);
         }
@@ -89,5 +213,11 @@ namespace boost {
 
 } // namespace boost
 
+#if defined(__clang__) || (defined(__GNUC__) && \
+    !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) && \
+    (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
+#pragma GCC diagnostic pop
+#endif
+
 #endif // BOOST_LEXICAL_CAST_TRY_LEXICAL_CONVERT_HPP
 

+ 3 - 2
contrib/restricted/boost/lexical_cast/ya.make

@@ -6,15 +6,16 @@ LICENSE(BSL-1.0)
 
 LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
 
-VERSION(1.85.0)
+VERSION(2024-01-24)
 
-ORIGINAL_SOURCE(https://github.com/boostorg/lexical_cast/archive/boost-1.85.0.tar.gz)
+ORIGINAL_SOURCE(https://github.com/boostorg/lexical_cast/archive/f0862bb60ddd56c3e5b4e413605c4e2528540ed6.tar.gz)
 
 PEERDIR(
     contrib/restricted/boost/config
     contrib/restricted/boost/container
     contrib/restricted/boost/core
     contrib/restricted/boost/integer
+    contrib/restricted/boost/numeric_conversion
     contrib/restricted/boost/throw_exception
     contrib/restricted/boost/type_traits
 )