File indexing completed on 2025-04-19 08:19:40
0001
0002
0003
0004
0005 #ifndef BOOST_FALLBACK_ROUTINES_HPP
0006 #define BOOST_FALLBACK_ROUTINES_HPP
0007
0008 #include <boost/charconv/detail/to_chars_integer_impl.hpp>
0009 #include <boost/charconv/detail/dragonbox/floff.hpp>
0010 #include <boost/charconv/detail/config.hpp>
0011 #include <boost/charconv/detail/from_chars_result.hpp>
0012 #include <boost/charconv/chars_format.hpp>
0013 #include <system_error>
0014 #include <type_traits>
0015 #include <locale>
0016 #include <clocale>
0017 #include <cstring>
0018 #include <cstdio>
0019
0020 namespace boost {
0021 namespace charconv {
0022 namespace detail {
0023
0024 template <typename T>
0025 inline int print_val(char* first, std::size_t size, char* format, T value) noexcept
0026 {
0027 return std::snprintf(first, size, format, value);
0028 }
0029
0030 template <typename T>
0031 to_chars_result to_chars_printf_impl(char* first, char* last, T value, chars_format fmt, int precision)
0032 {
0033
0034
0035 char format[14] {};
0036 std::memcpy(format, "%", 1);
0037 std::size_t pos = 1;
0038
0039
0040 if (precision != -1 && fmt != chars_format::fixed)
0041 {
0042 format[pos] = '.';
0043 ++pos;
0044 const auto unsigned_precision = static_cast<std::uint32_t>(precision);
0045 if (unsigned_precision < 10)
0046 {
0047 boost::charconv::detail::print_1_digit(unsigned_precision, format + pos);
0048 ++pos;
0049 }
0050 else if (unsigned_precision < 100)
0051 {
0052 boost::charconv::detail::print_2_digits(unsigned_precision, format + pos);
0053 pos += 2;
0054 }
0055 else
0056 {
0057 boost::charconv::detail::to_chars_int(format + pos, format + sizeof(format), precision);
0058 pos = std::strlen(format);
0059 }
0060 }
0061 else if (fmt == chars_format::fixed)
0062 {
0063
0064 std::memcpy(format + pos, ".0", 2);
0065 pos += 2;
0066 }
0067
0068
0069 BOOST_CHARCONV_IF_CONSTEXPR (std::is_same<T, long double>::value)
0070 {
0071 format[pos] = 'L';
0072 ++pos;
0073 }
0074
0075
0076 switch (fmt)
0077 {
0078 case boost::charconv::chars_format::general:
0079 format[pos] = 'g';
0080 break;
0081
0082 case boost::charconv::chars_format::scientific:
0083 format[pos] = 'e';
0084 break;
0085
0086 case boost::charconv::chars_format::fixed:
0087 format[pos] = 'f';
0088 break;
0089
0090 case boost::charconv::chars_format::hex:
0091 format[pos] = 'a';
0092 break;
0093 }
0094
0095 const auto rv = print_val(first, static_cast<std::size_t>(last - first), format, value);
0096
0097 if (rv <= 0)
0098 {
0099 return {last, static_cast<std::errc>(errno)};
0100 }
0101
0102 return {first + rv, std::errc()};
0103 }
0104
0105 #ifdef BOOST_MSVC
0106 # pragma warning(push)
0107 # pragma warning(disable: 4244)
0108 #elif defined(__GNUC__) && __GNUC__ >= 5
0109 # pragma GCC diagnostic push
0110 # pragma GCC diagnostic ignored "-Wmissing-field-initializers"
0111 # pragma GCC diagnostic ignored "-Wfloat-conversion"
0112 #elif defined(__clang__) && __clang_major__ > 7
0113 # pragma clang diagnostic push
0114 # pragma clang diagnostic ignored "-Wimplicit-float-conversion"
0115 #elif defined(__clang__) && __clang_major__ <= 7
0116 # pragma clang diagnostic push
0117 # pragma clang diagnostic ignored "-Wconversion"
0118 #endif
0119
0120
0121
0122
0123
0124
0125 inline void convert_string_locale(char* buffer) noexcept
0126 {
0127 const auto locale_decimal_point = *std::localeconv()->decimal_point;
0128 if (locale_decimal_point != '.')
0129 {
0130 auto p = std::strchr(buffer, '.');
0131 if (p != nullptr)
0132 {
0133 *p = locale_decimal_point;
0134 }
0135 }
0136 }
0137
0138 template <typename T>
0139 from_chars_result from_chars_strtod_impl(const char* first, const char* last, T& value, char* buffer) noexcept
0140 {
0141
0142
0143
0144
0145
0146 std::memcpy(buffer, first, static_cast<std::size_t>(last - first));
0147 buffer[last - first] = '\0';
0148 convert_string_locale(buffer);
0149
0150 char* str_end;
0151 T return_value {};
0152 from_chars_result r {nullptr, std::errc()};
0153
0154 BOOST_IF_CONSTEXPR (std::is_same<T, float>::value)
0155 {
0156 return_value = std::strtof(buffer, &str_end);
0157
0158 #ifndef __INTEL_LLVM_COMPILER
0159 if (return_value == HUGE_VALF)
0160 #else
0161 if (return_value >= std::numeric_limits<T>::max())
0162 #endif
0163 {
0164 r = {last, std::errc::result_out_of_range};
0165 }
0166 }
0167 else BOOST_IF_CONSTEXPR (std::is_same<T, double>::value)
0168 {
0169 return_value = std::strtod(buffer, &str_end);
0170
0171 #ifndef __INTEL_LLVM_COMPILER
0172 if (return_value == HUGE_VAL)
0173 #else
0174 if (return_value >= std::numeric_limits<T>::max())
0175 #endif
0176 {
0177 r = {last, std::errc::result_out_of_range};
0178 }
0179 }
0180 else BOOST_IF_CONSTEXPR (std::is_same<T, long double>::value)
0181 {
0182 return_value = std::strtold(buffer, &str_end);
0183
0184 #ifndef __INTEL_LLVM_COMPILER
0185 if (return_value == HUGE_VALL)
0186 #else
0187 if (return_value >= std::numeric_limits<T>::max())
0188 #endif
0189 {
0190 r = {last, std::errc::result_out_of_range};
0191 }
0192 }
0193
0194
0195 if (return_value == 0 && str_end == last)
0196 {
0197 r = {first, std::errc::result_out_of_range};
0198 }
0199
0200 if (r)
0201 {
0202 value = return_value;
0203 r = {first + (str_end - buffer), std::errc()};
0204 }
0205
0206 return r;
0207 }
0208
0209 template <typename T>
0210 inline from_chars_result from_chars_strtod(const char* first, const char* last, T& value) noexcept
0211 {
0212 if (last - first < 1024)
0213 {
0214 char buffer[1024];
0215 return from_chars_strtod_impl(first, last, value, buffer);
0216 }
0217
0218
0219
0220
0221 char* buffer = static_cast<char*>(std::malloc(static_cast<std::size_t>(last - first + 1)));
0222 if (buffer == nullptr)
0223 {
0224 return {first, std::errc::not_enough_memory};
0225 }
0226
0227 auto r = from_chars_strtod_impl(first, last, value, buffer);
0228 std::free(buffer);
0229
0230 return r;
0231 }
0232
0233 #ifdef BOOST_MSVC
0234 # pragma warning(pop)
0235 #elif defined(__GNUC__) && __GNUC__ >= 5
0236 # pragma GCC diagnostic pop
0237 #elif defined(__clang__)
0238 # pragma clang diagnostic pop
0239 #endif
0240
0241 }
0242 }
0243 }
0244
0245 #endif