fi
# For libtool versioning info, format is CURRENT:REVISION:AGE
-libtool_VERSION=6:28:0
+libtool_VERSION=6:29:0
# Everything parsed; figure out what files and settings to use.
case $enable_symvers in
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
+/* Define to 1 if you have the `uselocale' function. */
+#undef HAVE_USELOCALE
+
/* Defined if usleep exists. */
#undef HAVE_USLEEP
/* Define if writev is available in <sys/uio.h>. */
#undef HAVE_WRITEV
+/* Define to 1 if you have the <xlocale.h> header file. */
+#undef HAVE_XLOCALE_H
+
/* Define to 1 if you have the `_acosf' function. */
#undef HAVE__ACOSF
} GLIBCXX_3.4.27;
+GLIBCXX_3.4.29 {
+
+ # std::from_chars
+ _ZSt10from_charsPKcS0_R[def]St12chars_format;
+
+} GLIBCXX_3.4.28;
+
# Symbols in the support library (libsupc++) have their own tag.
CXXABI_1.3 {
__gnu_cxx_ldbl1287num_getI[cw]*16_M_extract_floatB5cxx11*;
} GLIBCXX_LDBL_3.4.10;
+GLIBCXX_LDBL_3.4.29 {
+ _ZSt10from_charsPKcS0_RgSt12chars_format;
+} GLIBCXX_LDBL_3.4.21;
+
CXXABI_LDBL_1.3 {
_ZT[IS]g;
_ZT[IS]Pg;
done
+for ac_header in xlocale.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "xlocale.h" "ac_cv_header_xlocale_h" "$ac_includes_default"
+if test "x$ac_cv_header_xlocale_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_XLOCALE_H 1
+_ACEOF
+
+fi
+
+done
+
+
# Only do link tests if native. Else, hardcode.
if $GLIBCXX_IS_NATIVE; then
#define HAVE_SOCKATMARK 1
_ACEOF
+fi
+done
+
+
+ # Non-standard functions used by C++17 std::from_chars
+ for ac_func in uselocale
+do :
+ ac_fn_c_check_func "$LINENO" "uselocale" "ac_cv_func_uselocale"
+if test "x$ac_cv_func_uselocale" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_USELOCALE 1
+_ACEOF
+
fi
done
fi
+
+ $as_echo "#define HAVE_USELOCALE 1" >>confdefs.h
+
;;
*-darwin*)
CXXFLAGS="$ac_save_CXXFLAGS"
+
+ for ac_func in uselocale
+do :
+ ac_fn_c_check_func "$LINENO" "uselocale" "ac_cv_func_uselocale"
+if test "x$ac_cv_func_uselocale" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_USELOCALE 1
+_ACEOF
+
+fi
+done
+
;;
*djgpp)
#define HAVE_SOCKATMARK 1
_ACEOF
+fi
+done
+
+ for ac_func in uselocale
+do :
+ ac_fn_c_check_func "$LINENO" "uselocale" "ac_cv_func_uselocale"
+if test "x$ac_cv_func_uselocale" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_USELOCALE 1
+_ACEOF
+
fi
done
fi
done
+ for ac_func in uselocale
+do :
+ ac_fn_c_check_func "$LINENO" "uselocale" "ac_cv_func_uselocale"
+if test "x$ac_cv_func_uselocale" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_USELOCALE 1
+_ACEOF
+
+fi
+done
+
fi
# For libtool versioning info, format is CURRENT:REVISION:AGE
-libtool_VERSION=6:28:0
+libtool_VERSION=6:29:0
# Everything parsed; figure out what files and settings to use.
case $enable_symvers in
#endif
]])
+AC_CHECK_HEADERS([xlocale.h])
+
# Only do link tests if native. Else, hardcode.
if $GLIBCXX_IS_NATIVE; then
# For Networking TS.
AC_CHECK_FUNCS(sockatmark)
+ # Non-standard functions used by C++17 std::from_chars
+ AC_CHECK_FUNCS(uselocale)
+
# For iconv support.
AM_ICONV
# We don't yet support AIX's TLS ABI.
#GCC_CHECK_TLS
AM_ICONV
+
+ AC_DEFINE(HAVE_USELOCALE)
;;
*-darwin*)
# Don't call GLIBCXX_CHECK_LINKER_FEATURES, Darwin doesn't have a GNU ld
GLIBCXX_CHECK_MATH_SUPPORT
GLIBCXX_CHECK_STDLIB_SUPPORT
+
+ AC_CHECK_FUNCS(uselocale)
;;
*djgpp)
AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign _aligned_malloc)
AC_CHECK_FUNCS(timespec_get)
AC_CHECK_FUNCS(sockatmark)
+ AC_CHECK_FUNCS(uselocale)
;;
*-fuchsia*)
AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign _aligned_malloc)
AC_CHECK_FUNCS(timespec_get)
AC_CHECK_FUNCS(sockatmark)
+ AC_CHECK_FUNCS(uselocale)
AM_ICONV
;;
*-mingw32*)
operator^=(chars_format& __lhs, chars_format __rhs) noexcept
{ return __lhs = __lhs ^ __rhs; }
+#if _GLIBCXX_HAVE_USELOCALE
+ from_chars_result
+ from_chars(const char* __first, const char* __last, float& __value,
+ chars_format __fmt = chars_format::general);
+
+ from_chars_result
+ from_chars(const char* __first, const char* __last, double& __value,
+ chars_format __fmt = chars_format::general);
+
+ from_chars_result
+ from_chars(const char* __first, const char* __last, long double& __value,
+ chars_format __fmt = chars_format::general);
+#endif
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // C++14
endif
sources = \
+ floating_from_chars.cc \
fs_dir.cc \
fs_ops.cc \
fs_path.cc \
libc__17convenience_la_LIBADD =
@ENABLE_DUAL_ABI_TRUE@am__objects_1 = cow-fs_dir.lo cow-fs_ops.lo \
@ENABLE_DUAL_ABI_TRUE@ cow-fs_path.lo
-am__objects_2 = fs_dir.lo fs_ops.lo fs_path.lo memory_resource.lo \
- $(am__objects_1)
+am__objects_2 = floating_from_chars.lo fs_dir.lo fs_ops.lo fs_path.lo \
+ memory_resource.lo $(am__objects_1)
@ENABLE_DUAL_ABI_TRUE@am__objects_3 = cow-string-inst.lo
@ENABLE_EXTERN_TEMPLATE_TRUE@am__objects_4 = ostream-inst.lo \
@ENABLE_EXTERN_TEMPLATE_TRUE@ string-inst.lo $(am__objects_3)
@ENABLE_EXTERN_TEMPLATE_TRUE@ $(extra_string_inst_sources)
sources = \
+ floating_from_chars.cc \
fs_dir.cc \
fs_ops.cc \
fs_path.cc \
--- /dev/null
+// std::from_chars implementation for floating-point types -*- C++ -*-
+
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+//
+// ISO C++ 14882:2017
+// 23.2.9 Primitive numeric input conversion [utility.from.chars]
+//
+
+#include <charconv>
+#include <string>
+#include <memory_resource>
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
+#include <cctype>
+#include <locale.h>
+#include <bits/functexcept.h>
+#if _GLIBCXX_HAVE_XLOCALE_H
+# include <xlocale.h>
+#endif
+
+#if _GLIBCXX_HAVE_USELOCALE
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+namespace
+{
+ // A memory resource with a static buffer that can be used for small
+ // allocations. At most one allocation using the freestore can be done
+ // if the static buffer is insufficient. The callers below only require
+ // a single allocation, so there's no need for anything more complex.
+ struct buffer_resource : pmr::memory_resource
+ {
+ ~buffer_resource() { if (m_ptr) operator delete(m_ptr, m_bytes); }
+
+ void*
+ do_allocate(size_t bytes, size_t alignment [[maybe_unused]]) override
+ {
+ // Allocate from the buffer if it will fit.
+ if (m_bytes < sizeof(m_buf) && (m_bytes + bytes) <= sizeof(m_buf))
+ return m_buf + std::__exchange(m_bytes, m_bytes + bytes);
+
+ __glibcxx_assert(m_ptr == nullptr);
+ __glibcxx_assert(alignment != 1);
+
+ m_ptr = operator new(bytes);
+ m_bytes = bytes;
+ return m_ptr;
+ }
+
+ void
+ do_deallocate(void*, size_t, size_t) noexcept override
+ { /* like pmr::monotonic_buffer_resource, do nothing here */ }
+
+ bool
+ do_is_equal(const pmr::memory_resource& other) const noexcept override
+ { return &other == this; }
+
+ static constexpr int guaranteed_capacity() { return sizeof(m_buf); }
+
+ private:
+ char m_buf[512];
+ size_t m_bytes = 0;
+ void* m_ptr = nullptr;
+ };
+
+ inline bool valid_fmt(chars_format fmt)
+ {
+ return fmt != chars_format{}
+ && ((fmt & chars_format::general) == fmt
+ || (fmt & chars_format::hex) == fmt);
+ }
+
+ constexpr char hex_digits[] = "abcdefABCDEF0123456789";
+ constexpr auto dec_digits = hex_digits + 12;
+
+ // Find initial portion of [first, last) containing a floating-point number.
+ // The string `digits` is either `dec_digits` or `hex_digits`
+ // and `exp` is 'e' or 'p' or '\0'.
+ const char*
+ find_end_of_float(const char* first, const char* last, const char* digits,
+ char exp)
+ {
+ while (first < last && strchr(digits, *first) != nullptr)
+ ++first;
+ if (first < last && *first == '.')
+ {
+ ++first;
+ while (first < last && strchr(digits, *first))
+ ++first;
+ }
+ if (first < last && exp != 0 && std::tolower((unsigned char)*first) == exp)
+ {
+ ++first;
+ if (first < last && (*first == '-' || *first == '+'))
+ ++first;
+ while (first < last && strchr(dec_digits, *first) != nullptr)
+ ++first;
+ }
+ return first;
+ }
+
+ // Determine the prefix of [first, last) that matches the pattern
+ // corresponding to `fmt`.
+ // Returns a NTBS containing the pattern, using `buf` to allocate
+ // additional storage if needed.
+ // Returns a nullptr if a valid pattern is not present.
+ const char*
+ pattern(const char* const first, const char* last,
+ chars_format& fmt, pmr::string& buf)
+ {
+ // fmt has the value of one of the enumerators of chars_format.
+ __glibcxx_assert(valid_fmt(fmt));
+
+ string_view res;
+
+ if (first == last || *first == '+') [[unlikely]]
+ return nullptr;
+
+ const int neg = (*first == '-');
+
+ if (std::memchr("iInN", (unsigned char)first[neg], 4))
+ {
+ ptrdiff_t len = last - first;
+ if (len < (3 + neg))
+ return nullptr;
+
+ // possible infinity or NaN, let strtod decide
+ if (first[neg] == 'i' || first[neg] == 'I')
+ {
+ // Need at most 9 chars for "-INFINITY", ignore anything after it.
+ len = std::min(len, ptrdiff_t(neg + 8));
+ }
+ else if (len > (neg + 3) && first[neg + 3] == '(')
+ {
+ // Look for end of "NAN(n-char-sequence)"
+ if (void* p = std::memchr(const_cast<char*>(first)+4, ')', len-4))
+ len = static_cast<char*>(p) + 1 - first;
+#ifndef __cpp_exceptions
+ if (len > buffer_resource::guaranteed_capacity())
+ {
+ // The character sequence is too large for the buffer.
+ // Allocation failure could terminate the process,
+ // so just return an error via the fmt parameter.
+ fmt = chars_format{};
+ return nullptr;
+ }
+#endif
+ }
+ else // Only need 4 chars for "-NAN"
+ len = neg + 3;
+
+ buf.assign(first, 0, len);
+ // prevent make_result correcting for "0x"
+ fmt = chars_format::general;
+ return buf.c_str();
+ }
+
+ const char* digits;
+ char* ptr;
+
+ // Assign [first,last) to a std::string to get a NTBS that can be used
+ // with strspn, strtod etc.
+ // If the string would be longer than the fixed buffer inside the
+ // buffer_resource type use find_end_of_float to try to reduce how
+ // much memory is needed, to reduce the chance of std::bad_alloc.
+
+ if (fmt == chars_format::hex)
+ {
+ digits = hex_digits;
+
+ if ((last - first + 2) > buffer_resource::guaranteed_capacity())
+ {
+ last = find_end_of_float(first + neg, last, digits, 'p');
+#ifndef __cpp_exceptions
+ if ((last - first + 2) > buffer_resource::guaranteed_capacity())
+ {
+ // The character sequence is still too large for the buffer.
+ // Allocation failure could terminate the process,
+ // so just return an error via the fmt parameter.
+ fmt = chars_format{};
+ return nullptr;
+ }
+#endif
+ }
+
+ buf = "-0x" + !neg;
+ buf.append(first + neg, last);
+ ptr = buf.data() + neg + 2;
+ }
+ else
+ {
+ digits = dec_digits;
+
+ if ((last - first) > buffer_resource::guaranteed_capacity())
+ {
+ last = find_end_of_float(first + neg, last, digits,
+ "e"[fmt == chars_format::fixed]);
+#ifndef __cpp_exceptions
+ if ((last - first) > buffer_resource::guaranteed_capacity())
+ {
+ // The character sequence is still too large for the buffer.
+ // Allocation failure could terminate the process,
+ // so just return an error via the fmt parameter.
+ fmt = chars_format{};
+ return nullptr;
+ }
+#endif
+ }
+ buf.assign(first, last);
+ ptr = buf.data() + neg;
+ }
+
+ // "A non-empty sequence of decimal digits" or
+ // "A non-empty sequence of hexadecimal digits"
+ size_t len = std::strspn(ptr, digits);
+ // "possibly containing a radix character,"
+ if (ptr[len] == '.')
+ {
+ const size_t len2 = std::strspn(ptr + len + 1, digits);
+ if (len + len2)
+ ptr += len + 1 + len2;
+ else
+ return nullptr;
+ }
+ else if (len == 0) [[unlikely]]
+ return nullptr;
+ else
+ ptr += len;
+
+ if (fmt == chars_format::fixed)
+ {
+ // Truncate the string to stop strtod parsing past this point.
+ *ptr = '\0';
+ }
+ else if (fmt == chars_format::scientific)
+ {
+ // Check for required exponent part which starts with 'e' or 'E'
+ if (*ptr != 'e' && *ptr != 'E')
+ return nullptr;
+ // then an optional plus or minus sign
+ const int sign = (ptr[1] == '-' || ptr[1] == '+');
+ // then a nonempty sequence of decimal digits
+ if (!std::memchr(dec_digits, (unsigned char)ptr[1+sign], 10))
+ return nullptr;
+ }
+ else if (fmt == chars_format::general)
+ {
+ if (*ptr == 'x' || *ptr == 'X')
+ *ptr = '\0';
+ }
+
+ return buf.c_str();
+ }
+
+ // Convert the NTBS `str` to a floating-point value of type `T`.
+ // If `str` cannot be converted, `value` is unchanged and `0` is returned.
+ // Otherwise, let N be the number of characters consumed from `str`.
+ // On success `value` is set to the converted value and N is returned.
+ // If the converted value is out of range, `value` is unchanged and
+ // -N is returned.
+ template<typename T>
+ ptrdiff_t
+ from_chars_impl(const char* str, T& value, errc& ec) noexcept
+ {
+ if (locale_t loc = ::newlocale(LC_ALL, "C", (locale_t)0)) [[likely]]
+ {
+ locale_t orig = ::uselocale(loc);
+
+ const int save_errno = errno;
+ errno = 0;
+ char* endptr;
+ T tmpval;
+ if constexpr (is_same_v<T, float>)
+ tmpval = std::strtof(str, &endptr);
+ if constexpr (is_same_v<T, double>)
+ tmpval = std::strtod(str, &endptr);
+ else if constexpr (is_same_v<T, long double>)
+ tmpval = std::strtold(str, &endptr);
+ const int conv_errno = std::__exchange(errno, save_errno);
+
+ ::uselocale(orig);
+ ::freelocale(loc);
+
+ const ptrdiff_t n = endptr - str;
+ if (conv_errno == ERANGE) [[unlikely]]
+ {
+ if (std::isinf(tmpval)) // overflow
+ ec = errc::result_out_of_range;
+ else // underflow (LWG 3081 wants to set value = tmpval here)
+ ec = errc::result_out_of_range;
+ }
+ else if (n)
+ {
+ value = tmpval;
+ ec = errc();
+ }
+ return n;
+ }
+ else if (errno == ENOMEM)
+ ec = errc::not_enough_memory;
+
+ return 0;
+ }
+
+ inline from_chars_result
+ make_result(const char* str, ptrdiff_t n, chars_format fmt, errc ec) noexcept
+ {
+ from_chars_result result = { str, ec };
+ if (n != 0)
+ {
+ if (fmt == chars_format::hex)
+ n -= 2; // correct for the "0x" inserted into the pattern
+ result.ptr += n;
+ }
+ else if (fmt == chars_format{}) [[unlikely]]
+ {
+ // FIXME: the standard does not allow this result.
+ ec = errc::not_enough_memory;
+ }
+ return result;
+ }
+
+} // namespace
+
+// FIXME: This should be reimplemented so it doesn't use strtod and newlocale.
+// That will avoid the need for any memory allocation, meaning that the
+// non-conforming errc::not_enough_memory result cannot happen.
+
+from_chars_result
+from_chars(const char* first, const char* last, float& value,
+ chars_format fmt) noexcept
+{
+ buffer_resource mr;
+ pmr::string buf(&mr);
+ size_t len = 0;
+ errc ec = errc::invalid_argument;
+ __try
+ {
+ if (const char* pat = pattern(first, last, fmt, buf)) [[likely]]
+ len = from_chars_impl(pat, value, ec);
+ }
+ __catch (const std::bad_alloc&)
+ {
+ fmt = chars_format{};
+ }
+ return make_result(first, len, fmt, ec);
+}
+
+from_chars_result
+from_chars(const char* first, const char* last, double& value,
+ chars_format fmt) noexcept
+{
+ buffer_resource mr;
+ pmr::string buf(&mr);
+ size_t len = 0;
+ errc ec = errc::invalid_argument;
+ __try
+ {
+ if (const char* pat = pattern(first, last, fmt, buf)) [[likely]]
+ len = from_chars_impl(pat, value, ec);
+ }
+ __catch (const std::bad_alloc&)
+ {
+ fmt = chars_format{};
+ }
+ return make_result(first, len, fmt, ec);
+}
+
+from_chars_result
+from_chars(const char* first, const char* last, long double& value,
+ chars_format fmt) noexcept
+{
+ buffer_resource mr;
+ pmr::string buf(&mr);
+ size_t len = 0;
+ errc ec = errc::invalid_argument;
+ __try
+ {
+ if (const char* pat = pattern(first, last, fmt, buf)) [[likely]]
+ len = from_chars_impl(pat, value, ec);
+ }
+ __catch (const std::bad_alloc&)
+ {
+ fmt = chars_format{};
+ }
+ return make_result(first, len, fmt, ec);
+}
+
+#ifdef _GLIBCXX_LONG_DOUBLE_COMPAT
+extern "C" from_chars_result
+_ZSt10from_charsPKcS0_ReSt12chars_format(const char* first, const char* last,
+ long double& value,
+ chars_format fmt) noexcept
+__attribute__((alias ("_ZSt10from_charsPKcS0_RdSt12chars_format")));
+#endif
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // _GLIBCXX_HAVE_USELOCALE
}
// { dg-prune-output "enable_if" }
+// { dg-prune-output "cannot bind non-const lvalue reference" }
}
// { dg-prune-output "enable_if" }
+// { dg-prune-output "cannot bind non-const lvalue reference" }
VERIFY( r.ptr == s.data() );
VERIFY( i == 999 );
+ s = "+1";
+ r = std::from_chars(s.data(), s.data() + s.length(), i);
+ VERIFY( r.ec == std::errc::invalid_argument );
+ VERIFY( r.ptr == s.data() );
+ VERIFY( i == 999 );
+
unsigned u = 888;
s = "-1";
r = std::from_chars(s.data(), s.data() + s.length(), u);
VERIFY( r.ec == std::errc::invalid_argument );
VERIFY( r.ptr == s.data() );
VERIFY( u == 888 );
+ s = "+1";
+ r = std::from_chars(s.data(), s.data() + s.length(), u);
+ VERIFY( r.ec == std::errc::invalid_argument );
+ VERIFY( r.ptr == s.data() );
+ VERIFY( u == 888 );
for (int base = 2; base <= 36; ++base)
{
--- /dev/null
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// <charconv> is supported in C++14 as a GNU extension
+// { dg-do run { target c++14 } }
+
+#include <charconv>
+#include <string>
+#include <limits>
+#include <cmath>
+#include <cstdlib>
+#include <testsuite_hooks.h>
+
+// Test std::from_chars floating-point conversions.
+
+void
+test01()
+{
+ std::string s;
+ double d;
+ std::from_chars_result res;
+
+ for (auto fmt : { std::chars_format::fixed, std::chars_format::scientific,
+ std::chars_format::general, std::chars_format::hex })
+ {
+ s = "Info";
+ res = std::from_chars(s.data(), s.data() + s.length(), d, fmt);
+ VERIFY( std::isinf(d) );
+ VERIFY( res.ptr == s.data() + 3 );
+ VERIFY( res.ec == std::errc{} );
+
+ s = "-INFIN";
+ res = std::from_chars(s.data(), s.data() + s.length(), d, fmt);
+ VERIFY( std::isinf(d) );
+ VERIFY( d < 0 );
+ VERIFY( res.ptr == s.data() + 4 );
+ VERIFY( res.ec == std::errc{} );
+
+ s = "InFiNiTy aNd BeYoNd";
+ res = std::from_chars(s.data(), s.data() + s.length(), d, fmt);
+ VERIFY( std::isinf(d) );
+ VERIFY( res.ptr == s.data() + 8 );
+ VERIFY( res.ec == std::errc{} );
+
+ s = "nAn";
+ res = std::from_chars(s.data(), s.data() + s.length(), d, fmt);
+ VERIFY( std::isnan(d) );
+ VERIFY( res.ptr == s.data() + 3 );
+ VERIFY( res.ec == std::errc{} );
+
+ s = "-NAN()";
+ res = std::from_chars(s.data(), s.data() + s.length(), d, fmt);
+ VERIFY( std::isnan(d) );
+ VERIFY( res.ptr == s.data() + s.length() );
+ VERIFY( res.ec == std::errc{} );
+ }
+}
+
+void
+test02()
+{
+ std::string s;
+ double d = 1.0;
+ std::from_chars_result res;
+
+ s = "0x123";
+ res = std::from_chars(s.data(), s.data() + s.length(), d);
+ VERIFY( d == 0.0 );
+ VERIFY( res.ptr == s.data() + 1 );
+ VERIFY( res.ec == std::errc{} );
+
+ d = 1.0;
+ res = std::from_chars(s.data(), s.data() + s.length(), d,
+ std::chars_format::fixed);
+ VERIFY( d == 0.0 );
+ VERIFY( res.ptr == s.data() + 1 );
+ VERIFY( res.ec == std::errc{} );
+
+ d = 1.0;
+ res = std::from_chars(s.data(), s.data() + s.length(), d,
+ std::chars_format::scientific);
+ VERIFY( d == 1.0 );
+ VERIFY( res.ptr == s.data() );
+ VERIFY( res.ec == std::errc::invalid_argument );
+
+ d = 1.0;
+ res = std::from_chars(s.data(), s.data() + s.length(), d,
+ std::chars_format::general);
+ VERIFY( d == 0.0 );
+ VERIFY( res.ptr == s.data() + 1 );
+ VERIFY( res.ec == std::errc{} );
+
+ d = 1.0;
+ res = std::from_chars(s.data(), s.data() + s.length(), d,
+ std::chars_format::hex);
+ VERIFY( d == 0.0 );
+ VERIFY( res.ptr == s.data() + 1 );
+ VERIFY( res.ec == std::errc{} );
+}
+
+void
+test03()
+{
+ std::string s;
+ double d = 1.0;
+ std::from_chars_result res;
+
+ s = "0.5e+2azzz";
+ res = std::from_chars(s.data(), s.data() + s.length(), d);
+ VERIFY( d == 0.5e+2 );
+ VERIFY( res.ptr == s.data() + s.length() - 1 - 3 );
+ VERIFY( res.ec == std::errc{} );
+
+ res = std::from_chars(s.data(), s.data() + s.length(), d,
+ std::chars_format::fixed);
+ VERIFY( d == 0.5 );
+ VERIFY( res.ptr == s.data() + 3 );
+ VERIFY( res.ec == std::errc{} );
+
+ d = 1.0;
+ res = std::from_chars(s.data(), s.data() + s.length(), d,
+ std::chars_format::scientific);
+ VERIFY( d == 0.5e+2 );
+ VERIFY( res.ptr == s.data() + s.length() - 1 - 3 );
+ VERIFY( res.ec == std::errc{} );
+
+ d = 1.0;
+ res = std::from_chars(s.data(), s.data() + s.length(), d,
+ std::chars_format::general);
+ VERIFY( d == 0.5e+2 );
+ VERIFY( res.ptr == s.data() + s.length() - 1 - 3 );
+ VERIFY( res.ec == std::errc{} );
+
+ d = 1.0;
+ res = std::from_chars(s.data(), s.data() + s.length(), d,
+ std::chars_format::hex);
+ VERIFY( d == 0x0.5Ep0 );
+ VERIFY( res.ptr == s.data() + 4 );
+ VERIFY( res.ec == std::errc{} );
+
+ s = "1.Ap-2zzz";
+ res = std::from_chars(s.data(), s.data() + s.length(), d,
+ std::chars_format::hex);
+ VERIFY( d == 0.40625 );
+ VERIFY( res.ptr == s.data() + s.length() - 3 );
+ VERIFY( res.ec == std::errc{} );
+}
+
+void
+test04()
+{
+ // Huge input strings
+ std::string s(1000, '0');
+ double d = 1.0;
+ std::from_chars_result res;
+ res = std::from_chars(s.data(), s.data() + s.length(), d);
+ VERIFY( res.ptr == s.data() + s.length() );
+ VERIFY( res.ec == std::errc{} );
+ VERIFY( d == 0.0 );
+
+ s += ".5";
+ res = std::from_chars(s.data(), s.data() + s.length(), d);
+ VERIFY( res.ptr == s.data() + s.length() );
+ VERIFY( res.ec == std::errc{} );
+ VERIFY( d == 0.5 );
+
+ s += "e2";
+ auto len = s.length();
+ s += std::string(1000, 'a');
+ res = std::from_chars(s.data(), s.data() + s.length(), d);
+ VERIFY( res.ptr == s.data() + len );
+ VERIFY( res.ec == std::errc{} );
+ VERIFY( d == 50 );
+}
+
+using std::to_string;
+
+#ifdef __GLIBCXX_TYPE_INT_N_0
+std::string
+to_string(unsigned __GLIBCXX_TYPE_INT_N_0 val)
+{
+ using Limits = std::numeric_limits<unsigned __GLIBCXX_TYPE_INT_N_0>;
+ std::string s(Limits::digits10+2, '0');
+ for (auto iter = s.end(); val != 0; val /= 10)
+ *--iter = '0' + (val % 10);
+ return s;
+}
+#endif
+
+void
+test05()
+{
+ std::from_chars_result res;
+ float flt;
+ double dbl;
+ long double ldbl;
+
+ // Small integer values that are exactly representable
+
+ for (int i = 0; i < 100; ++i)
+ {
+ std::string s = to_string(i);
+ int len = s.length();
+ s += "123";
+ const char* s1 = s.c_str();
+ const char* s1_end = s1 + len;
+
+ for (auto fmt : { std::chars_format::fixed,
+ std::chars_format::general,
+ std::chars_format::hex })
+ {
+ if (fmt == std::chars_format::hex && i > 9)
+ continue;
+
+ res = std::from_chars(s1, s1_end, flt, fmt);
+ VERIFY( res.ec == std::errc{} );
+ VERIFY( res.ptr == s1_end );
+ VERIFY( flt == i );
+
+ res = std::from_chars(s1, s1_end, dbl, fmt);
+ VERIFY( res.ec == std::errc{} );
+ VERIFY( res.ptr == s1_end );
+ VERIFY( dbl == i );
+
+ res = std::from_chars(s1, s1_end, ldbl, fmt);
+ VERIFY( res.ec == std::errc{} );
+ VERIFY( res.ptr == s1_end );
+ VERIFY( ldbl == i );
+ }
+
+ if (i > 9)
+ continue;
+
+ // Test single-digit integers with small exponents.
+
+ const char s2[] = { '.', *s1, 'e', '0', '0', '0', '1' };
+ const char* s2_end = s2 + sizeof(s2);
+
+ const char s3[] = { *s1, '0', 'e', '-', '0', '0', '1' };
+ const char* s3_end = s3 + sizeof(s3);
+
+ for (auto fmt : { std::chars_format::scientific,
+ std::chars_format::general })
+ {
+ res = std::from_chars(s2, s2_end, flt, fmt);
+ VERIFY( res.ec == std::errc{} );
+ VERIFY( res.ptr == s2_end );
+ VERIFY( flt == i );
+
+ res = std::from_chars(s3, s3_end, flt, fmt);
+ VERIFY( res.ec == std::errc{} );
+ VERIFY( res.ptr == s3_end );
+ VERIFY( flt == i );
+
+ res = std::from_chars(s2, s2_end, dbl, fmt);
+ VERIFY( res.ec == std::errc{} );
+ VERIFY( res.ptr == s2_end );
+ VERIFY( dbl == i );
+
+ res = std::from_chars(s3, s3_end, dbl, fmt);
+ VERIFY( res.ec == std::errc{} );
+ VERIFY( res.ptr == s3_end );
+ VERIFY( dbl == i );
+
+ res = std::from_chars(s2, s2_end, ldbl, fmt);
+ VERIFY( res.ec == std::errc{} );
+ VERIFY( res.ptr == s2_end );
+ VERIFY( ldbl == i );
+
+ res = std::from_chars(s3, s3_end, ldbl, fmt);
+ VERIFY( res.ec == std::errc{} );
+ VERIFY( res.ptr == s3_end );
+ VERIFY( ldbl == i );
+ }
+ }
+}
+
+template<typename FloatT, typename UIntT>
+void
+test_max_mantissa()
+{
+ using Float_limits = std::numeric_limits<FloatT>;
+ using UInt_limits = std::numeric_limits<UIntT>;
+
+ if constexpr (Float_limits::is_iec559
+ && Float_limits::digits < UInt_limits::digits)
+ {
+ std::printf("Testing %d-bit float, using %zu-bit integer\n",
+ Float_limits::digits + (int)std::log2(Float_limits::max_exponent) + 1,
+ sizeof(UIntT) * __CHAR_BIT__);
+
+ std::from_chars_result res;
+ FloatT flt;
+
+ for (int i = 0; i < 10; ++i)
+ {
+ // (1 << digits) - 1 is the maximum value of the mantissa
+ const auto val = ((UIntT)1 << Float_limits::digits) - 1 - i;
+ std::string s = to_string(val);
+ auto len = s.length();
+ s += "000"; // these should be ignored
+ for (auto fmt : { std::chars_format::fixed,
+ std::chars_format::general })
+ {
+ res = std::from_chars(s.data(), s.data() + len, flt, fmt);
+ VERIFY( res.ec == std::errc{} );
+ VERIFY( res.ptr == s.data() + len );
+ VERIFY( flt == val );
+ }
+ s.resize(len);
+ const auto orig_len = len;
+ s += "e+000";
+ len = s.length();
+ s += "111";
+ for (auto fmt : { std::chars_format::scientific,
+ std::chars_format::general })
+ {
+ res = std::from_chars(s.data(), s.data() + len, flt, fmt);
+ VERIFY( res.ec == std::errc{} );
+ VERIFY( res.ptr == s.data() + len );
+ VERIFY( flt == val );
+
+ std::string s2 = s.substr(0, len - 5);
+ s2.insert(s2.cbegin() + orig_len - 1, '.');
+ s2 += "e000000000001";
+ res = std::from_chars(s.data(), s.data() + len, flt, fmt);
+ VERIFY( res.ec == std::errc{} );
+ VERIFY( res.ptr == s.data() + len );
+ VERIFY( flt == val );
+ }
+ }
+ }
+}
+
+void
+test06()
+{
+ test_max_mantissa<float, unsigned long>();
+ test_max_mantissa<double, unsigned long long>();
+#ifdef __GLIBCXX_TYPE_INT_N_0
+ test_max_mantissa<long double, unsigned __GLIBCXX_TYPE_INT_N_0>();
+#endif
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+ test06();
+}
--- /dev/null
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// <charconv> is supported in C++14 as a GNU extension
+// { dg-do run { target c++14 } }
+
+#include <charconv>
+#include <string>
+#include <cmath>
+#include <testsuite_hooks.h>
+
+// Test std::from_chars error handling.
+
+void
+test01()
+{
+ std::from_chars_result r;
+ double d = 3.2;
+ std::string s;
+
+ for (auto p : { "", "*", ".", "-", "-*", "-.", "+", "+.", "+-", "-+", "+1",
+ ".p1", "-.p1",
+ "in", "inch", "+inf", "na", "nam", "+nan" })
+ {
+ s = p;
+ for (auto fmt : { std::chars_format::fixed, std::chars_format::scientific,
+ std::chars_format::general, std::chars_format::hex })
+ {
+ r = std::from_chars(s.data(), s.data() + s.length(), d, fmt);
+ VERIFY( r.ec == std::errc::invalid_argument );
+ VERIFY( r.ptr == s.data() );
+ VERIFY( d == 3.2 );
+ }
+ }
+
+ for (auto p : { ".e1", "-.e1" }) // These are valid patterns for hex format
+ {
+ s = p;
+ for (auto fmt : { std::chars_format::fixed, std::chars_format::scientific,
+ std::chars_format::general })
+ {
+ r = std::from_chars(s.data(), s.data() + s.length(), d, fmt);
+ VERIFY( r.ec == std::errc::invalid_argument );
+ VERIFY( r.ptr == s.data() );
+ VERIFY( d == 3.2 );
+ }
+ }
+
+ // scientific format requires an exponent
+ for (auto p : { "1.2", "-1.2", "1.2e", "-1.2e", "1.2e-", "-1.2e+" })
+ {
+ s = p;
+ r = std::from_chars(s.data(), s.data() + s.length(), d,
+ std::chars_format::scientific);
+ VERIFY( r.ec == std::errc::invalid_argument );
+ VERIFY( r.ptr == s.data() );
+ VERIFY( d == 3.2 );
+ }
+
+ // patterns that are invalid without the final character
+ for (auto p : { "1", ".1", "-1", "-.1",
+ "inf", "-inf", "nan", "-nan" })
+ {
+ s = p;
+ for (auto fmt : { std::chars_format::fixed, std::chars_format::scientific,
+ std::chars_format::general, std::chars_format::hex })
+ {
+ r = std::from_chars(s.data(), s.data() + s.length() - 1, d, fmt);
+ VERIFY( r.ec == std::errc::invalid_argument );
+ VERIFY( r.ptr == s.data() );
+ VERIFY( d == 3.2 );
+ }
+ }
+}
+
+void
+test02()
+{
+ std::from_chars_result r;
+ std::string s;
+
+ float f = 0.5;
+ // Overflow
+ s = "99999999999999999e999999999999999999";
+ r = std::from_chars(s.data(), s.data() + s.length(), f);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.data() + s.length() );
+ VERIFY( f == 0.5 );
+
+ s += '*';
+ r = std::from_chars(s.data(), s.data() + s.length(), f);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.data() + s.length() - 1 );
+ VERIFY( f == 0.5 );
+
+ s.insert(s.begin(), '-');
+ r = std::from_chars(s.data(), s.data() + s.length(), f);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.data() + s.length() - 1 );
+ VERIFY( f == 0.5 );
+}
+
+void
+test03()
+{
+ double d = 0.5;
+ // Underflow
+ std::string s("-1.2345e-9999zzz");
+ std::from_chars_result res;
+ res = std::from_chars(s.data(), s.data() + s.length(), d);
+ VERIFY( res.ptr == s.data() + s.length() - 3 );
+ VERIFY( res.ec == std::errc::result_out_of_range );
+ VERIFY( d == 0.5 );
+
+ res = std::from_chars(s.data() + 1, s.data() + s.length(), d);
+ VERIFY( res.ptr == s.data() + s.length() - 3 );
+ VERIFY( res.ec == std::errc::result_out_of_range );
+ VERIFY( d == 0.5 );
+}
+
+void
+test04()
+{
+ std::from_chars_result res;
+ std::string z(2000, '0');
+ // Invalid inputs for scientific format
+ for (const char* s : { "", "1", ".", ".0", ".5", "1e+", "1e+-1" })
+ {
+ for (auto len : { 0, 10, 100, 1000, 2000 })
+ {
+ auto str = z.substr(len) + s;
+ double d = 99.0;
+ res = std::from_chars(str.data(), str.data() + str.length(), d,
+ std::chars_format::scientific);
+ VERIFY( res.ec == std::errc::invalid_argument );
+ VERIFY( res.ptr == str.data() );
+ VERIFY( d == 99.0 );
+ }
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+}
known_versions.push_back("GLIBCXX_3.4.26");
known_versions.push_back("GLIBCXX_3.4.27");
known_versions.push_back("GLIBCXX_3.4.28");
+ known_versions.push_back("GLIBCXX_3.4.29");
+ known_versions.push_back("GLIBCXX_LDBL_3.4.29");
known_versions.push_back("CXXABI_1.3");
known_versions.push_back("CXXABI_LDBL_1.3");
known_versions.push_back("CXXABI_1.3.1");
test.version_status = symbol::incompatible;
// Check that added symbols are added in the latest pre-release version.
- bool latestp = (test.version_name == "GLIBCXX_3.4.28"
+ bool latestp = (test.version_name == "GLIBCXX_3.4.29"
+ // XXX remove next line when GLIBCXX_3.4.30 is added and baselines
+ // have been regenerated to include GLIBCXX_LDBL_3.4.29 symbols:
+ || test.version_name == "GLIBCXX_LDBL_3.4.29"
|| test.version_name == "CXXABI_1.3.12"
|| test.version_name == "CXXABI_FLOAT128"
|| test.version_name == "CXXABI_TM_1");