Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-19 08:19:40

0001 // Copyright 2024 Matt Borland
0002 // Distributed under the Boost Software License, Version 1.0.
0003 // https://www.boost.org/LICENSE_1_0.txt
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     // v % + . + num_digits(INT_MAX) + specifier + null terminator
0034     // 1 + 1 + 10 + 1 + 1
0035     char format[14] {};
0036     std::memcpy(format, "%", 1); // NOLINT : No null terminator is purposeful
0037     std::size_t pos = 1;
0038 
0039     // precision of -1 is unspecified
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         // Force 0 decimal places
0064         std::memcpy(format + pos, ".0", 2); // NOLINT : No null terminator is purposeful
0065         pos += 2;
0066     }
0067 
0068     // Add the type identifier
0069     BOOST_CHARCONV_IF_CONSTEXPR (std::is_same<T, long double>::value)
0070     {
0071         format[pos] = 'L';
0072         ++pos;
0073     }
0074 
0075     // Add the format character
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) // Implict converion when BOOST_IF_CONSTEXPR expands to if
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 // We know that the string is in the "C" locale because it would have previously passed through our parser.
0121 // Convert the string into the current locale so that the strto* family of functions
0122 // works correctly for the given locale.
0123 //
0124 // We are operating on our own copy of the buffer, so we are free to modify it.
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     // For strto(f/d)
0142     // Floating point value corresponding to the contents of str on success.
0143     // If the converted value falls out of range of corresponding return type, range error occurs and HUGE_VAL, HUGE_VALF or HUGE_VALL is returned.
0144     // If no conversion can be performed, 0 is returned and *str_end is set to str.
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     // Since this is a fallback routine we are safe to check for 0
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     // If the string to be parsed does not fit into the 1024 byte static buffer than we have to allocate a buffer.
0219     // malloc is used here because it does not throw on allocation failure.
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 } //namespace detail
0242 } //namespace charconv
0243 } //namespace boost
0244 
0245 #endif //BOOST_FALLBACK_ROUTINES_HPP