public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Define std::to_chars and std::from_chars for C++17 (P0067R5, partial)
@ 2017-04-07 12:29 Jonathan Wakely
  2017-04-10 13:07 ` Jonathan Wakely
  0 siblings, 1 reply; 4+ messages in thread
From: Jonathan Wakely @ 2017-04-07 12:29 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1871 bytes --]

This adds another piece of the C++17 library, the std::to_chars and
std::from_chars functions for converting numbers to/from strings. This
only adds the integer support, floating point types will require a lot
more work.

This has only been lightly optimised, so it beats printf on average,
but there's probably more opportunity for improvement. I didn't
investigate whether doing all work with unsigned long long would be
faster, instead of using function templates specialized for unsigned
int, unsigned long and unsigned long long. It should help code size,
but I don't know if it would be faster. I also didn't investigate
whether doing from_chars in two stages would be better, i.e. finding
all the characters that are valid digits in the given base first, and
then converting them to an integer in a second step. I'm sure there's
lots of tuning that could be done, but I hope this is good enough to
start with.

Although the new functions are only defined by <utility> for C++17,
the implementation doesn't require C++17. so directly including
<bits/string_conv.h> makes them available in C++14. Non-portably, of
course.

	* include/Makefile.am: Add <bits/string_conv.h>.
	* include/Makefile.in: Regenerate.
	* include/bits/string_conv.h: New file.
	(to_chars_result, to_chars, from_chars_result, from_chars): Define.
	* include/std/utility: Include <bits/string_conv.h>.
	* testsuite/20_util/from_chars/1.cc: New test.
	* testsuite/20_util/from_chars/1_neg.cc: New test.
	* testsuite/20_util/from_chars/2.cc: New test.
	* testsuite/20_util/from_chars/requirements.cc: New test.
	* testsuite/20_util/to_chars/1.cc: New test.
	* testsuite/20_util/to_chars/1_neg.cc: New test.
	* testsuite/20_util/to_chars/2.cc: New test.
	* testsuite/20_util/to_chars/requirements.cc: New test.

Any suggestions for immediate improvement?

Any reason not to commit this to trunk?



[-- Attachment #2: patch.txt --]
[-- Type: text/x-patch, Size: 62115 bytes --]

commit ac6a4efed8de8f4b397ca27bee8d88123ca05d22
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Apr 7 12:11:12 2017 +0100

    Define std::to_chars and std::from_chars for C++17 (P0067R5, partial)
    
    	* include/Makefile.am: Add <bits/string_conv.h>.
    	* include/Makefile.in: Regenerate.
    	* include/bits/string_conv.h: New file.
    	(to_chars_result, to_chars, from_chars_result, from_chars): Define.
    	* include/std/utility: Include <bits/string_conv.h>.
    	* testsuite/20_util/from_chars/1.cc: New test.
    	* testsuite/20_util/from_chars/1_neg.cc: New test.
    	* testsuite/20_util/from_chars/2.cc: New test.
    	* testsuite/20_util/from_chars/requirements.cc: New test.
    	* testsuite/20_util/to_chars/1.cc: New test.
    	* testsuite/20_util/to_chars/1_neg.cc: New test.
    	* testsuite/20_util/to_chars/2.cc: New test.
    	* testsuite/20_util/to_chars/requirements.cc: New test.

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 3703bd1..c8c073c 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -190,6 +190,7 @@ bits_headers = \
 	${bits_srcdir}/streambuf_iterator.h \
 	${bits_srcdir}/streambuf.tcc \
 	${bits_srcdir}/stringfwd.h \
+	${bits_srcdir}/string_conv.h \
 	${bits_srcdir}/string_view.tcc \
 	${bits_srcdir}/uniform_int_dist.h \
 	${bits_srcdir}/unique_ptr.h \
diff --git a/libstdc++-v3/include/bits/string_conv.h b/libstdc++-v3/include/bits/string_conv.h
new file mode 100644
index 0000000..330c0a8
--- /dev/null
+++ b/libstdc++-v3/include/bits/string_conv.h
@@ -0,0 +1,420 @@
+// Implementation of std::to_chars and std::from_chars -*- C++ -*-
+
+// Copyright (C) 2017 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/>.
+
+/** @file include/bits/string_conv.h
+ *  This is an internal header file, included by other library headers.
+ *  Do not attempt to use it directly. @headername{utility}
+ */
+
+#ifndef _GLIBCXX_STRING_CONV_H
+#define _GLIBCXX_STRING_CONV_H 1
+
+#pragma GCC system_header
+
+#if __cplusplus < 201402L
+# include <bits/c++14_warning.h>
+#else
+
+#include <system_error>
+#include <limits>
+#include <cctype>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  struct to_chars_result {
+    char* ptr;
+    error_code ec;
+  };
+
+  struct from_chars_result {
+    const char* ptr;
+    error_code ec;
+  };
+
+_GLIBCXX_END_NAMESPACE_VERSION
+namespace __detail{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+  template<typename _Tp, typename... _Types>
+    using __is_one_of = __or_<is_same<_Tp, _Types>...>;
+
+  template<typename _Tp>
+    using __is_to_chars_type = __and_<is_integral<_Tp>,
+	  __not_<__is_one_of<_Tp, bool, char16_t, char32_t
+#if _GLIBCXX_USE_WCHAR_T
+	  , wchar_t
+#endif
+	    >>>;
+
+  template<typename _Tp>
+    using __to_chars_result_type
+      = enable_if_t<__is_to_chars_type<_Tp>::value, to_chars_result>;
+
+  template<typename _Tp>
+    using __unsigned_least_t
+      = conditional_t<(sizeof(_Tp) <= sizeof(int)), unsigned int,
+	conditional_t<(sizeof(_Tp) <= sizeof(long)), unsigned long,
+	conditional_t<(sizeof(_Tp) <= sizeof(long long)), unsigned long long,
+#if _GLIBCXX_USE_INT128
+	conditional_t<(sizeof(_Tp) <= sizeof(__int128)), unsigned __int128,
+#endif
+	void>>>>;
+
+  template<typename _Tp>
+    constexpr unsigned
+    __to_chars_len(_Tp __value, int __base = 10)
+    {
+      static_assert(is_integral<_Tp>::value, "implementation bug");
+      static_assert(is_unsigned<_Tp>::value, "implementation bug");
+
+      unsigned __n = 1;
+      const int __b2 = __base  * __base;
+      const int __b3 = __b2 * __base;
+      const int __b4 = __b3 * __base;
+      for (;;)
+	{
+	  if (__value < __base) return __n;
+	  if (__value < __b2) return __n + 1;
+	  if (__value < __b3) return __n + 2;
+	  if (__value < __b4) return __n + 3;
+	  __value /= (unsigned)__b4;
+	  __n += 4;
+	}
+    }
+
+  template<typename _Tp>
+    to_chars_result
+    __to_chars(char* __first, char* __last, _Tp __val, int __base)
+    {
+      static_assert(is_integral<_Tp>::value, "implementation bug");
+      static_assert(is_unsigned<_Tp>::value, "implementation bug");
+
+      constexpr char __digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+
+      to_chars_result __res;
+
+      const unsigned __len = __to_chars_len(__val, __base);
+
+      if (__builtin_expect((__last - __first) < __len, 0))
+	{
+	  __res.ptr = __last;
+	  __res.ec = std::make_error_code(errc::value_too_large);
+	  return __res;
+	}
+
+      unsigned __pos = __len - 1;
+
+      if (__base == 10)
+	{
+	  constexpr char __digits[201] =
+	    "0001020304050607080910111213141516171819"
+	    "2021222324252627282930313233343536373839"
+	    "4041424344454647484950515253545556575859"
+	    "6061626364656667686970717273747576777879"
+	    "8081828384858687888990919293949596979899";
+	  while (__val >= 100)
+	    {
+	      auto const __num = (__val % 100) * 2;
+	      __val /= 100;
+	      __first[__pos] = __digits[__num + 1];
+	      __first[__pos - 1] = __digits[__num];
+	      __pos -= 2;
+	    }
+	  if (__val >= 10)
+	    {
+	      auto const __num = __val * 2;
+	      __first[__pos] = __digits[__num + 1];
+	      __first[__pos - 1] = __digits[__num];
+	    }
+	  else
+	    __first[__pos] = '0' + __val;
+	}
+      else if (__base == 8)
+	{
+	  constexpr char __digits[129] =
+	    "00010203040506071011121314151617"
+	    "20212223242526273031323334353637"
+	    "40414243444546475051525354555657"
+	    "60616263646566677071727374757677";
+	  while (__val >= 64)
+	    {
+	      auto const __num = (__val % 64) * 2;
+	      __val /= 64;
+	      __first[__pos] = __digits[__num + 1];
+	      __first[__pos - 1] = __digits[__num];
+	      __pos -= 2;
+	    }
+	  if (__val >= 8)
+	    {
+	      auto const __num = __val * 2;
+	      __first[__pos] = __digits[__num + 1];
+	      __first[__pos - 1] = __digits[__num];
+	    }
+	  else
+	    __first[__pos] = '0' + __val;
+	}
+      else if (__base == 2)
+	{
+	  while (__pos)
+	    {
+	      __first[__pos--] = '0' + (__val & 1);
+	      __val >>= 1;
+	    }
+	  *__first = '0' + (__val & 1);
+	}
+      else
+	{
+	  while (__val >= __base)
+	    {
+	      auto const __quo = __val / __base;
+	      auto const __rem = __val % __base;
+	      __first[__pos--] = __digits[__rem];
+	      __val = __quo;
+	    }
+	  *__first = __digits[__val];
+	}
+      __res.ptr = __first + __len;
+      return __res;
+    }
+_GLIBCXX_END_NAMESPACE_VERSION
+}
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  template<typename _Tp>
+    __detail::__to_chars_result_type<_Tp>
+    to_chars(char* __first, char* __last, _Tp __value, int __base = 10)
+    {
+      __glibcxx_assert(2 <= __base && __base <= 36);
+
+      using _Up = __detail::__unsigned_least_t<_Tp>;
+      _Up __unsigned_val = __value;
+
+      if _GLIBCXX17_CONSTEXPR (std::is_signed<_Tp>::value)
+	if (__value < 0)
+	  {
+	    if (__builtin_expect(__first != __last, 1))
+	      *__first++ = '-';
+	    __unsigned_val = _Up(~__value) + _Up(1);
+	  }
+
+      return __detail::__to_chars(__first, __last, __unsigned_val, __base);
+    }
+
+_GLIBCXX_END_NAMESPACE_VERSION
+namespace __detail {
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  template<typename _Tp>
+    bool
+    __raise_and_add(_Tp& __val, int __base, unsigned char __c)
+    {
+      if (__builtin_mul_overflow(__val, __base, &__val)
+	  || __builtin_add_overflow(__val, __c, &__val))
+	return false;
+      return true;
+    }
+
+  template<typename _Tp>
+    bool
+    __from_chars_binary(const char*& __first, const char* __last, _Tp& __val)
+    {
+      static_assert(is_integral<_Tp>::value, "implementation bug");
+      static_assert(is_unsigned<_Tp>::value, "implementation bug");
+
+      const ptrdiff_t __len = __last - __first;
+      int __i = 0;
+      while (__i < __len)
+	{
+	  if (__first[__i] == '0')
+	      __val <<= 1;
+	  else if (__first[__i] == '1')
+	      (__val <<= 1) |= 1;
+	  else
+	    break;
+	  __i++;
+	}
+      __first += __i;
+      return __i <= (sizeof(_Tp) * __CHAR_BIT__);
+    }
+
+  template<typename _Tp>
+    bool
+    __from_chars_digit(const char*& __first, const char* __last, _Tp& __val,
+		       int __base)
+    {
+      static_assert(is_integral<_Tp>::value, "implementation bug");
+      static_assert(is_unsigned<_Tp>::value, "implementation bug");
+
+      auto __matches = [__base](char __c) {
+	  return '0' <= __c && __c <= ('0' + (__base - 1));
+      };
+
+      while (__first != __last)
+	{
+	  const char __c = *__first;
+	  if (__matches(__c))
+	  {
+	    if (!__raise_and_add(__val, __base, __c - '0'))
+	      {
+		while (++__first != __last && __matches(*__first))
+		  ;
+		return false;
+	      }
+	    __first++;
+	  }
+	  else
+	    return true;
+	}
+      return true;
+    }
+
+  constexpr bool __consecutive_chars(const char* __s, int __n)
+  {
+    for (int __i = 1; __i < __n; ++__i)
+      if (__s[__i] != (__s[__i-1] + 1))
+	return false;
+    return true;
+  }
+
+  template<typename _Tp>
+    bool
+    __from_chars_alnum(const char*& __first, const char* __last, _Tp& __val,
+		       int __base)
+    {
+      const int __b = __base - 10;
+      bool __valid = true;
+      while (__first != __last)
+	{
+	  unsigned char __c = *__first;
+	  if (std::isdigit(__c))
+	    __c -= '0';
+	  else
+	    {
+	      constexpr char __abc[] = "abcdefghijklmnopqrstuvwxyz";
+	      unsigned char __lc = std::tolower(__c);
+	      constexpr bool __consecutive = __consecutive_chars(__abc, 26);
+	      if _GLIBCXX17_CONSTEXPR (__consecutive)
+		{
+		  // Characters 'a'..'z' are consecutive
+		  if (std::isalpha(__c) && (__lc - 'a') < __b)
+		    __c = __lc - 'a' + 10;
+		  else
+		    break;
+		}
+	      else
+		{
+		  if (auto __p = __builtin_memchr(__abc, __lc, __b))
+		    __c = static_cast<const char*>(__p) - __abc;
+		  else
+		    break;
+		}
+	    }
+
+	  if (__builtin_expect(__valid, 1))
+	    __valid = __raise_and_add(__val, __base, __c);
+	  __first++;
+	}
+      return __valid;
+    }
+
+  template<typename _Tp>
+    using __from_chars_result_type
+      = enable_if_t<__is_to_chars_type<_Tp>::value, from_chars_result>;
+
+_GLIBCXX_END_NAMESPACE_VERSION
+}
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  template<typename _Tp>
+    __detail::__from_chars_result_type<_Tp>
+    from_chars(const char* __first, const char* __last, _Tp& __value,
+	       int __base = 10)
+    {
+      __glibcxx_assert(2 <= __base && __base <= 36);
+
+      from_chars_result __res{__first, {}};
+
+      int __sign = 1;
+      if _GLIBCXX17_CONSTEXPR (std::is_signed<_Tp>::value)
+	if (__first != __last && *__first == '-')
+	  {
+	    __sign = -1;
+	    ++__first;
+	  }
+
+      using _Up = __detail::__unsigned_least_t<_Tp>;
+      _Up __val = 0;
+
+      const auto __start = __first;
+      bool __valid;
+      if (__base == 2)
+	__valid = __detail::__from_chars_binary(__first, __last, __val);
+      else if (__base <= 10)
+	__valid = __detail::__from_chars_digit(__first, __last, __val, __base);
+      else
+	__valid = __detail::__from_chars_alnum(__first, __last, __val, __base);
+
+      if (__builtin_expect(__first == __start, 0))
+	__res.ec = std::make_error_code(errc::invalid_argument);
+      else
+	{
+	  __res.ptr = __first;
+	  if (!__valid)
+	    __res.ec = std::make_error_code(errc::result_out_of_range);
+	  else
+	    {
+	      if _GLIBCXX17_CONSTEXPR (std::is_signed<_Tp>::value)
+		{
+		  _Tp __tmp;
+		  if (__builtin_mul_overflow(__val, __sign, &__tmp))
+		    __res.ec = make_error_code(errc::result_out_of_range);
+		  else
+		    __value = __tmp;
+		}
+	      else
+		{
+		  if _GLIBCXX17_CONSTEXPR
+		    (numeric_limits<_Up>::max() > numeric_limits<_Tp>::max())
+		    {
+		      if (__val > numeric_limits<_Tp>::max())
+			__res.ec = make_error_code(errc::result_out_of_range);
+		      else
+			__value = __val;
+		    }
+		  else
+		    __value = __val;
+		}
+	    }
+	}
+
+      return __res;
+    }
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // C++11
+
+#endif // _GLIBCXX_STRING_CONV_H
diff --git a/libstdc++-v3/include/std/utility b/libstdc++-v3/include/std/utility
index 188fcc2..acbf1a0 100644
--- a/libstdc++-v3/include/std/utility
+++ b/libstdc++-v3/include/std/utility
@@ -77,6 +77,7 @@
 
 #if __cplusplus > 201402L
 #include <exception>
+#include <bits/string_conv.h>
 #endif
 
 namespace std _GLIBCXX_VISIBILITY(default)
diff --git a/libstdc++-v3/testsuite/20_util/from_chars/1.cc b/libstdc++-v3/testsuite/20_util/from_chars/1.cc
new file mode 100644
index 0000000..ed94d23
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/from_chars/1.cc
@@ -0,0 +1,80 @@
+// Copyright (C) 2017 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++1z } }
+
+#include <utility>
+#include <string_view>
+
+template<typename I>
+bool
+check_from_chars(I expected, std::string_view s, int base = 0, char term = '\0')
+{
+  I val;
+  std::from_chars_result r = base == 0
+    ? std::from_chars(s.begin(), s.end(), val)
+    : std::from_chars(s.begin(), s.end(), val, base);
+  return !r.ec && (r.ptr == s.end() || *r.ptr == term) && val == expected;
+}
+
+#include <climits>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  // Using base 10
+  VERIFY( check_from_chars(123, "123") );
+  VERIFY( check_from_chars(-123, "-123") );
+  VERIFY( check_from_chars(123, "123a", 10, 'a') );
+  VERIFY( check_from_chars(123, "0000000000000000000000000000123") );
+  VERIFY( check_from_chars(123, "0000000000000000000000000000123a", 10, 'a') );
+}
+
+void
+test02()
+{
+  // "0x" parsed as "0" not as hex prefix:
+  VERIFY( check_from_chars(0, "0x1", 10, 'x') );
+  VERIFY( check_from_chars(0, "0X1", 10, 'X') );
+  VERIFY( check_from_chars(0, "0x1", 16, 'x') );
+  VERIFY( check_from_chars(0, "0X1", 16, 'X') );
+
+  VERIFY( check_from_chars(1155, "xx", 34) );
+  VERIFY( check_from_chars(1155, "XX", 34) );
+  VERIFY( check_from_chars(1155, "Xx", 34) );
+  VERIFY( check_from_chars(1224, "yy", 35) );
+  VERIFY( check_from_chars(1224, "YY", 35) );
+  VERIFY( check_from_chars(1224, "yY", 35) );
+  VERIFY( check_from_chars(1295, "zz", 36) );
+  VERIFY( check_from_chars(1295, "ZZ", 36) );
+  VERIFY( check_from_chars(1295, "Zz", 36) );
+
+  // Parsing stops at first invalid digit for the given base:
+  VERIFY( check_from_chars(1, "01234", 2, '2') );
+  VERIFY( check_from_chars(27, "1234", 4, '4') );
+  VERIFY( check_from_chars(1155, "xxy", 34, 'y') );
+  VERIFY( check_from_chars(1224, "yyz", 35, 'z') );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/20_util/from_chars/1_neg.cc b/libstdc++-v3/testsuite/20_util/from_chars/1_neg.cc
new file mode 100644
index 0000000..6eb5572
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/from_chars/1_neg.cc
@@ -0,0 +1,38 @@
+// Copyright (C) 2017 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++1z } }
+
+#include <utility>
+
+void
+test01(const char* first, const char* last)
+{
+#if _GLIBCXX_USE_WCHAR_T
+  wchar_t wc;
+  std::from_chars(first, last, wc); // { dg-error "no matching" }
+  std::from_chars(first, last, wc, 10); // { dg-error "no matching" }
+#endif
+
+  char16_t c16;
+  std::from_chars(first, last, c16); // { dg-error "no matching" }
+  std::from_chars(first, last, c16, 10); // { dg-error "no matching" }
+  char32_t c32;
+  std::from_chars(first, last, c32); // { dg-error "no matching" }
+  std::from_chars(first, last, c32, 10); // { dg-error "no matching" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/from_chars/2.cc b/libstdc++-v3/testsuite/20_util/from_chars/2.cc
new file mode 100644
index 0000000..3cb54ad
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/from_chars/2.cc
@@ -0,0 +1,205 @@
+// Copyright (C) 2017 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++1z } }
+
+#include <utility>
+#include <string_view>
+#include <testsuite_hooks.h>
+
+// Test std::from_chars error handling.
+
+void
+test01()
+{
+  std::from_chars_result r;
+  int i = 999;
+  std::string_view s;
+
+  s = "";
+  r = std::from_chars(s.begin(), s.end(), i);
+  VERIFY( r.ec == std::errc::invalid_argument );
+  VERIFY( r.ptr == s.begin() );
+  VERIFY( i == 999 );
+
+  s = "*";
+  r = std::from_chars(s.begin(), s.end(), i);
+  VERIFY( r.ec == std::errc::invalid_argument );
+  VERIFY( r.ptr == s.begin() );
+  VERIFY( i == 999 );
+
+  s = "-";
+  r = std::from_chars(s.begin(), s.end(), i);
+  VERIFY( r.ec == std::errc::invalid_argument );
+  VERIFY( r.ptr == s.begin() );
+  VERIFY( i == 999 );
+
+  s = "-*";
+  r = std::from_chars(s.begin(), s.end(), i);
+  VERIFY( r.ec == std::errc::invalid_argument );
+  VERIFY( r.ptr == s.begin() );
+  VERIFY( i == 999 );
+
+  unsigned u = 888;
+  s = "-1";
+  r = std::from_chars(s.begin(), s.end(), u);
+  VERIFY( r.ec == std::errc::invalid_argument );
+  VERIFY( r.ptr == s.begin() );
+  s = "-a";
+  r = std::from_chars(s.begin(), s.end(), u);
+  VERIFY( r.ec == std::errc::invalid_argument );
+  VERIFY( r.ptr == s.begin() );
+  s = "-";
+  r = std::from_chars(s.begin(), s.end(), u);
+  VERIFY( r.ec == std::errc::invalid_argument );
+  VERIFY( r.ptr == s.begin() );
+  VERIFY( u == 888 );
+
+  for (int base = 2; base <= 36; ++base)
+  {
+    const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz*";
+    const char buf[2] = { '-', digits[base] };
+    r = std::from_chars(buf, buf + 1, i, base);
+    VERIFY( r.ec == std::errc::invalid_argument );
+    VERIFY( r.ptr == buf );
+    VERIFY( i == 999 );
+    r = std::from_chars(buf + 1, buf + 2, i, base);
+    VERIFY( r.ec == std::errc::invalid_argument );
+    VERIFY( r.ptr == buf + 1 );
+    VERIFY( i == 999 );
+    r = std::from_chars(buf, buf + 2, i, base);
+    VERIFY( r.ec == std::errc::invalid_argument );
+    VERIFY( r.ptr == buf );
+    VERIFY( i == 999 );
+  }
+}
+
+void
+test02()
+{
+  std::from_chars_result r;
+  std::string_view s;
+
+  signed char c = -5;
+  s = "-10000001";
+  r = std::from_chars(s.begin(), s.end(), c, 2);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.end() );
+  s = "-10000001*";
+  r = std::from_chars(s.begin(), s.end(), c, 2);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.begin() + 9 );
+  s = "-10000001000*";
+  r = std::from_chars(s.begin(), s.end(), c, 2);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.begin() + 12 );
+  s = "-129";
+  r = std::from_chars(s.begin(), s.end(), c, 10);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.end() );
+  s = "-129*";
+  r = std::from_chars(s.begin(), s.end(), c, 10);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.begin() + 4 );
+  s = "-100";
+  r = std::from_chars(s.begin(), s.end(), c, 16);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.end() );
+  s = "-100*";
+  r = std::from_chars(s.begin(), s.end(), c, 16);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.begin() + 4 );
+  s = "-81";
+  r = std::from_chars(s.begin(), s.end(), c, 16);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.end() );
+  s = "-81*";
+  r = std::from_chars(s.begin(), s.end(), c, 16);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.begin() + 3 );
+  s = "128";
+  r = std::from_chars(s.begin(), s.end(), c, 10);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.end() );
+  s = "128*";
+  r = std::from_chars(s.begin(), s.end(), c, 10);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.begin() + 3 );
+  s = "80";
+  r = std::from_chars(s.begin(), s.end(), c, 16);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.end() );
+  s = "80*";
+  r = std::from_chars(s.begin(), s.end(), c, 16);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.begin() + 2 );
+  VERIFY( c == -5 );
+
+  unsigned char uc = 9;
+  s = "100000000";
+  r = std::from_chars(s.begin(), s.end(), uc, 2);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.end() );
+  s = "100000000*";
+  r = std::from_chars(s.begin(), s.end(), uc, 2);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.begin() + 9 );
+  s = "100000000000*";
+  r = std::from_chars(s.begin(), s.end(), uc, 2);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.begin() + 12 );
+  s = "256";
+  r = std::from_chars(s.begin(), s.end(), uc, 10);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.end() );
+  s = "256**";
+  r = std::from_chars(s.begin(), s.end(), uc, 10);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.begin() + 3 );
+  s = "256000**";
+  r = std::from_chars(s.begin(), s.end(), uc, 10);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.begin() + 6 );
+  s = "100";
+  r = std::from_chars(s.begin(), s.end(), uc, 16);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.end() );
+  s = "100**";
+  r = std::from_chars(s.begin(), s.end(), uc, 16);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.begin() + 3 );
+  s = "100000**";
+  r = std::from_chars(s.begin(), s.end(), uc, 16);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.begin() + 6 );
+  VERIFY( uc == 9 );
+
+  unsigned long long ull = 123;
+  s = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz****";
+  r = std::from_chars(s.begin(), s.end(), ull, 36);
+  VERIFY( r.ec == std::errc::result_out_of_range );
+  VERIFY( r.ptr == s.begin() + 42 );
+  VERIFY( ull == 123 );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+}
diff --git a/libstdc++-v3/testsuite/20_util/from_chars/requirements.cc b/libstdc++-v3/testsuite/20_util/from_chars/requirements.cc
new file mode 100644
index 0000000..378882e
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/from_chars/requirements.cc
@@ -0,0 +1,61 @@
+// Copyright (C) 2017 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++1z } }
+
+#include <utility>
+
+namespace std
+{
+  struct from_chars_result;
+
+  const char* from_chars_result::*pm2 = &from_chars_result::ptr;
+  error_code from_chars_result::*pm1 = &from_chars_result::ec;
+
+  from_chars_result (*f1)(const char*, const char*, char&, int)
+    = &from_chars;
+  from_chars_result (*f2)(const char*, const char*, signed char&, int)
+    = &from_chars;
+  from_chars_result (*f3)(const char*, const char*, unsigned char&, int)
+    = &from_chars;
+  from_chars_result (*f4)(const char*, const char*, signed short&, int)
+    = &from_chars;
+  from_chars_result (*f5)(const char*, const char*, unsigned short&, int)
+    = &from_chars;
+  from_chars_result (*f6)(const char*, const char*, signed int&, int)
+    = &from_chars;
+  from_chars_result (*f7)(const char*, const char*, unsigned int&, int)
+    = &from_chars;
+  from_chars_result (*f8)(const char*, const char*, signed long&, int)
+    = &from_chars;
+  from_chars_result (*f9)(const char*, const char*, unsigned long&, int)
+    = &from_chars;
+  from_chars_result (*f10)(const char*, const char*, signed long long&, int)
+    = &from_chars;
+  from_chars_result (*f11)(const char*, const char*, unsigned long long&, int)
+    = &from_chars;
+}
+
+void bind()
+{
+  const char buf[1] = "";
+  int i;
+  auto [p, e] = std::from_chars(buf, buf + 1, i, 10);
+  const char** pa = std::addressof(p);
+  std::error_code* ea = std::addressof(e);
+}
diff --git a/libstdc++-v3/testsuite/20_util/to_chars/1.cc b/libstdc++-v3/testsuite/20_util/to_chars/1.cc
new file mode 100644
index 0000000..c5a4165
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/to_chars/1.cc
@@ -0,0 +1,661 @@
+// Copyright (C) 2017 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++1z } }
+
+#include <utility>
+#include <string_view>
+
+template<typename I>
+bool
+check_to_chars(I val, std::string_view expected, int base = 0)
+{
+  // Space for minus sign, 64 binary digits, final '*', and null terminator:
+  char buf[67] = "******************************************************************";
+  std::to_chars_result r = base == 0
+    ? std::to_chars(buf, buf+sizeof(buf), val)
+    : std::to_chars(buf, buf+sizeof(buf), val, base);
+  return !r.ec && *r.ptr == '*' && std::string_view(buf, r.ptr - buf) == expected;
+}
+
+#include <string>
+#include <climits>
+#include <testsuite_hooks.h>
+
+// Using default base 10
+void
+test01()
+{
+  VERIFY( check_to_chars<char>(0, "0") );
+  VERIFY( check_to_chars<signed char>(0, "0") );
+  VERIFY( check_to_chars<unsigned char>(0, "0") );
+  VERIFY( check_to_chars<signed short>(0, "0") );
+  VERIFY( check_to_chars<unsigned short>(0, "0") );
+  VERIFY( check_to_chars<signed int>(0, "0") );
+  VERIFY( check_to_chars<unsigned int>(0, "0") );
+  VERIFY( check_to_chars<signed long>(0, "0") );
+  VERIFY( check_to_chars<unsigned long>(0, "0") );
+  VERIFY( check_to_chars<signed long long>(0, "0") );
+  VERIFY( check_to_chars<unsigned long long>(0, "0") );
+
+  VERIFY( check_to_chars<char>(1, "1") );
+  VERIFY( check_to_chars<signed char>(1, "1") );
+  VERIFY( check_to_chars<unsigned char>(1, "1") );
+  VERIFY( check_to_chars<signed short>(1, "1") );
+  VERIFY( check_to_chars<unsigned short>(1, "1") );
+  VERIFY( check_to_chars<signed int>(1, "1") );
+  VERIFY( check_to_chars<unsigned int>(1, "1") );
+  VERIFY( check_to_chars<signed long>(1, "1") );
+  VERIFY( check_to_chars<unsigned long>(1, "1") );
+  VERIFY( check_to_chars<signed long long>(1, "1") );
+  VERIFY( check_to_chars<unsigned long long>(1, "1") );
+
+  VERIFY( check_to_chars<char>(123, "123") );
+  VERIFY( check_to_chars<signed char>(123, "123") );
+  VERIFY( check_to_chars<unsigned char>(123, "123") );
+  VERIFY( check_to_chars<signed short>(123, "123") );
+  VERIFY( check_to_chars<unsigned short>(123, "123") );
+  VERIFY( check_to_chars<signed int>(123, "123") );
+  VERIFY( check_to_chars<unsigned int>(123, "123") );
+  VERIFY( check_to_chars<signed long>(123, "123") );
+  VERIFY( check_to_chars<unsigned long>(123, "123") );
+  VERIFY( check_to_chars<signed long long>(123, "123") );
+  VERIFY( check_to_chars<unsigned long long>(123, "123") );
+
+  if constexpr (std::is_signed_v<char>)
+    VERIFY( check_to_chars<char>(-79, "-79") );
+  VERIFY( check_to_chars<signed char>(-79, "-79") );
+  VERIFY( check_to_chars<signed short>(-79, "-79") );
+  VERIFY( check_to_chars<signed int>(-79, "-79") );
+  VERIFY( check_to_chars<signed long>(-79, "-79") );
+  VERIFY( check_to_chars<signed long long>(-79, "-79") );
+
+  using std::to_string;
+
+  VERIFY( check_to_chars<char>(CHAR_MAX, to_string(CHAR_MAX)) );
+  VERIFY( check_to_chars<signed char>(SCHAR_MAX, to_string(SCHAR_MAX)) );
+  VERIFY( check_to_chars<unsigned char>(UCHAR_MAX, to_string(UCHAR_MAX)) );
+  VERIFY( check_to_chars<signed short>(SHRT_MAX, to_string(SHRT_MAX)) );
+  VERIFY( check_to_chars<unsigned short>(USHRT_MAX, to_string(USHRT_MAX)) );
+  VERIFY( check_to_chars<signed int>(INT_MAX, to_string(INT_MAX)) );
+  VERIFY( check_to_chars<unsigned int>(UINT_MAX, to_string(UINT_MAX)) );
+  VERIFY( check_to_chars<signed long>(LONG_MAX, to_string(LONG_MAX)) );
+  VERIFY( check_to_chars<unsigned long>(ULONG_MAX, to_string(ULONG_MAX)) );
+  VERIFY( check_to_chars<signed long long>(LLONG_MAX, to_string(LLONG_MAX)) );
+  VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX, to_string(ULLONG_MAX)) );
+
+  VERIFY( check_to_chars<char>(CHAR_MIN, to_string(CHAR_MIN)) );
+  VERIFY( check_to_chars<signed char>(SCHAR_MIN, to_string(SCHAR_MIN)) );
+  VERIFY( check_to_chars<signed short>(SHRT_MIN, to_string(SHRT_MIN)) );
+  VERIFY( check_to_chars<signed int>(INT_MIN, to_string(INT_MIN)) );
+  VERIFY( check_to_chars<signed long>(LONG_MIN, to_string(LONG_MIN)) );
+  VERIFY( check_to_chars<signed long long>(LLONG_MIN, to_string(LLONG_MIN)) );
+
+  VERIFY( check_to_chars<char>(CHAR_MAX/2, to_string(CHAR_MAX/2)) );
+  VERIFY( check_to_chars<signed char>(SCHAR_MAX/2, to_string(SCHAR_MAX/2)) );
+  VERIFY( check_to_chars<unsigned char>(UCHAR_MAX/2, to_string(UCHAR_MAX/2)) );
+  VERIFY( check_to_chars<signed short>(SHRT_MAX/2, to_string(SHRT_MAX/2)) );
+  VERIFY( check_to_chars<unsigned short>(USHRT_MAX/2, to_string(USHRT_MAX/2)) );
+  VERIFY( check_to_chars<signed int>(INT_MAX/2, to_string(INT_MAX/2)) );
+  VERIFY( check_to_chars<unsigned int>(UINT_MAX/2, to_string(UINT_MAX/2)) );
+  VERIFY( check_to_chars<signed long>(LONG_MAX/2, to_string(LONG_MAX/2)) );
+  VERIFY( check_to_chars<unsigned long>(ULONG_MAX/2, to_string(ULONG_MAX/2)) );
+  VERIFY( check_to_chars<signed long long>(LLONG_MAX/2, to_string(LLONG_MAX/2)) );
+  VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX/2, to_string(ULLONG_MAX/2)) );
+}
+
+// Using explicit base 10
+void
+test02()
+{
+  VERIFY( check_to_chars<char>(0, "0", 10) );
+  VERIFY( check_to_chars<signed char>(0, "0", 10) );
+  VERIFY( check_to_chars<unsigned char>(0, "0", 10) );
+  VERIFY( check_to_chars<signed short>(0, "0", 10) );
+  VERIFY( check_to_chars<unsigned short>(0, "0", 10) );
+  VERIFY( check_to_chars<signed int>(0, "0", 10) );
+  VERIFY( check_to_chars<unsigned int>(0, "0", 10) );
+  VERIFY( check_to_chars<signed long>(0, "0", 10) );
+  VERIFY( check_to_chars<unsigned long>(0, "0", 10) );
+  VERIFY( check_to_chars<signed long long>(0, "0", 10) );
+  VERIFY( check_to_chars<unsigned long long>(0, "0", 10) );
+
+  VERIFY( check_to_chars<char>(1, "1", 10) );
+  VERIFY( check_to_chars<signed char>(1, "1", 10) );
+  VERIFY( check_to_chars<unsigned char>(1, "1", 10) );
+  VERIFY( check_to_chars<signed short>(1, "1", 10) );
+  VERIFY( check_to_chars<unsigned short>(1, "1", 10) );
+  VERIFY( check_to_chars<signed int>(1, "1", 10) );
+  VERIFY( check_to_chars<unsigned int>(1, "1", 10) );
+  VERIFY( check_to_chars<signed long>(1, "1", 10) );
+  VERIFY( check_to_chars<unsigned long>(1, "1", 10) );
+  VERIFY( check_to_chars<signed long long>(1, "1", 10) );
+  VERIFY( check_to_chars<unsigned long long>(1, "1", 10) );
+
+  VERIFY( check_to_chars<char>(123, "123", 10) );
+  VERIFY( check_to_chars<signed char>(123, "123", 10) );
+  VERIFY( check_to_chars<unsigned char>(123, "123", 10) );
+  VERIFY( check_to_chars<signed short>(123, "123", 10) );
+  VERIFY( check_to_chars<unsigned short>(123, "123", 10) );
+  VERIFY( check_to_chars<signed int>(123, "123", 10) );
+  VERIFY( check_to_chars<unsigned int>(123, "123", 10) );
+  VERIFY( check_to_chars<signed long>(123, "123", 10) );
+  VERIFY( check_to_chars<unsigned long>(123, "123", 10) );
+  VERIFY( check_to_chars<signed long long>(123, "123", 10) );
+  VERIFY( check_to_chars<unsigned long long>(123, "123", 10) );
+
+  if constexpr (std::is_signed_v<char>)
+    VERIFY( check_to_chars<char>(-79, "-79", 10) );
+  VERIFY( check_to_chars<signed char>(-79, "-79", 10) );
+  VERIFY( check_to_chars<signed short>(-79, "-79", 10) );
+  VERIFY( check_to_chars<signed int>(-79, "-79", 10) );
+  VERIFY( check_to_chars<signed long>(-79, "-79", 10) );
+  VERIFY( check_to_chars<signed long long>(-79, "-79", 10) );
+
+  using std::to_string;
+
+  VERIFY( check_to_chars<char>(CHAR_MAX, to_string(CHAR_MAX), 10) );
+  VERIFY( check_to_chars<signed char>(SCHAR_MAX, to_string(SCHAR_MAX), 10) );
+  VERIFY( check_to_chars<unsigned char>(UCHAR_MAX, to_string(UCHAR_MAX), 10) );
+  VERIFY( check_to_chars<signed short>(SHRT_MAX, to_string(SHRT_MAX), 10) );
+  VERIFY( check_to_chars<unsigned short>(USHRT_MAX, to_string(USHRT_MAX), 10) );
+  VERIFY( check_to_chars<signed int>(INT_MAX, to_string(INT_MAX), 10) );
+  VERIFY( check_to_chars<unsigned int>(UINT_MAX, to_string(UINT_MAX), 10) );
+  VERIFY( check_to_chars<signed long>(LONG_MAX, to_string(LONG_MAX), 10) );
+  VERIFY( check_to_chars<unsigned long>(ULONG_MAX, to_string(ULONG_MAX), 10) );
+  VERIFY( check_to_chars<signed long long>(LLONG_MAX, to_string(LLONG_MAX), 10) );
+  VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX, to_string(ULLONG_MAX), 10) );
+
+  VERIFY( check_to_chars<char>(CHAR_MIN, to_string(CHAR_MIN), 10) );
+  VERIFY( check_to_chars<signed char>(SCHAR_MIN, to_string(SCHAR_MIN), 10) );
+  VERIFY( check_to_chars<signed short>(SHRT_MIN, to_string(SHRT_MIN), 10) );
+  VERIFY( check_to_chars<signed int>(INT_MIN, to_string(INT_MIN), 10) );
+  VERIFY( check_to_chars<signed long>(LONG_MIN, to_string(LONG_MIN), 10) );
+  VERIFY( check_to_chars<signed long long>(LLONG_MIN, to_string(LLONG_MIN), 10) );
+
+  VERIFY( check_to_chars<char>(CHAR_MAX/2, to_string(CHAR_MAX/2), 10) );
+  VERIFY( check_to_chars<signed char>(SCHAR_MAX/2, to_string(SCHAR_MAX/2), 10) );
+  VERIFY( check_to_chars<unsigned char>(UCHAR_MAX/2, to_string(UCHAR_MAX/2), 10) );
+  VERIFY( check_to_chars<signed short>(SHRT_MAX/2, to_string(SHRT_MAX/2), 10) );
+  VERIFY( check_to_chars<unsigned short>(USHRT_MAX/2, to_string(USHRT_MAX/2), 10) );
+  VERIFY( check_to_chars<signed int>(INT_MAX/2, to_string(INT_MAX/2), 10) );
+  VERIFY( check_to_chars<unsigned int>(UINT_MAX/2, to_string(UINT_MAX/2), 10) );
+  VERIFY( check_to_chars<signed long>(LONG_MAX/2, to_string(LONG_MAX/2), 10) );
+  VERIFY( check_to_chars<unsigned long>(ULONG_MAX/2, to_string(ULONG_MAX/2), 10) );
+  VERIFY( check_to_chars<signed long long>(LLONG_MAX/2, to_string(LLONG_MAX/2), 10) );
+  VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX/2, to_string(ULLONG_MAX/2), 10) );
+}
+
+// Using all bases
+void
+test03()
+{
+  // -2017 in all bases from [2,36]
+  const char* str2017[37] = { nullptr, nullptr,
+    "-11111100001",
+    "-2202201",
+    "-133201",
+    "-31032",
+    "-13201",
+    "-5611",
+    "-3741",
+    "-2681",
+    "-2017",
+    "-1574",
+    "-1201",
+    "-bc2",
+    "-a41",
+    "-8e7",
+    "-7e1",
+    "-6gb",
+    "-641",
+    "-5b3",
+    "-50h",
+    "-4c1",
+    "-43f",
+    "-3ig",
+    "-3c1",
+    "-35h",
+    "-2pf",
+    "-2kj",
+    "-2g1",
+    "-2bg",
+    "-277",
+    "-232",
+    "-1v1",
+    "-1s4",
+    "-1pb",
+    "-1mm",
+    "-1k1"
+  };
+  // -12345 in all bases from [2,36]
+  const char* str12345[37] = { nullptr, nullptr,
+    "-11000000111001",
+    "-121221020",
+    "-3000321",
+    "-343340",
+    "-133053",
+    "-50664",
+    "-30071",
+    "-17836",
+    "-12345",
+    "-9303",
+    "-7189",
+    "-5808",
+    "-46db",
+    "-39d0",
+    "-3039",
+    "-28c3",
+    "-221f",
+    "-1f3e",
+    "-1ah5",
+    "-16ki",
+    "-13b3",
+    "-107h",
+    "-la9",
+    "-jik",
+    "-i6l",
+    "-gp6",
+    "-fkp",
+    "-ejk",
+    "-dlf",
+    "-cq7",
+    "-c1p",
+    "-bb3",
+    "-an3",
+    "-a2p",
+    "-9ix"
+  };
+  // -23456 in all bases from [2,36]
+  const char* str23456[37] = { nullptr, nullptr,
+    "-101101110100000",
+    "-1012011202",
+    "-11232200",
+    "-1222311",
+    "-300332",
+    "-125246",
+    "-55640",
+    "-35152",
+    "-23456",
+    "-16694",
+    "-116a8",
+    "-a8a4",
+    "-8796",
+    "-6e3b",
+    "-5ba0",
+    "-4d2d",
+    "-4072",
+    "-37ia",
+    "-2icg",
+    "-2b3k",
+    "-24a4",
+    "-1l7j",
+    "-1gh8",
+    "-1cd6",
+    "-18i4",
+    "-154k",
+    "-11pk",
+    "-rpo",
+    "-q1q",
+    "-ock",
+    "-mt0",
+    "-lhq",
+    "-k9u",
+    "-j56",
+    "-i3k"
+  };
+  // INT_MIN in all bases from [2,36]
+  const char* strINT_MIN[37] = { nullptr, nullptr,
+    "-10000000000000000000000000000000",
+    "-12112122212110202102",
+    "-2000000000000000",
+    "-13344223434043",
+    "-553032005532",
+    "-104134211162",
+    "-20000000000",
+    "-5478773672",
+    "-2147483648",
+    "-a02220282",
+    "-4bb2308a8",
+    "-282ba4aab",
+    "-1652ca932",
+    "-c87e66b8",
+    "-80000000",
+    "-53g7f549",
+    "-3928g3h2",
+    "-27c57h33",
+    "-1db1f928",
+    "-140h2d92",
+    "-ikf5bf2",
+    "-ebelf96",
+    "-b5gge58",
+    "-8jmdnkn",
+    "-6oj8ioo",
+    "-5ehnckb",
+    "-4clm98g",
+    "-3hk7988",
+    "-2sb6cs8",
+    "-2d09uc2",
+    "-2000000",
+    "-1lsqtl2",
+    "-1d8xqrq",
+    "-15v22un",
+    "-zik0zk"
+  };
+
+  for (int base = 2; base <= 36; ++base)
+  {
+    VERIFY( check_to_chars<char>(0, "0", base) );
+    VERIFY( check_to_chars<signed char>(0, "0", base) );
+    VERIFY( check_to_chars<unsigned char>(0, "0", base) );
+    VERIFY( check_to_chars<signed short>(0, "0", base) );
+    VERIFY( check_to_chars<unsigned short>(0, "0", base) );
+    VERIFY( check_to_chars<signed int>(0, "0", base) );
+    VERIFY( check_to_chars<unsigned int>(0, "0", base) );
+    VERIFY( check_to_chars<signed long>(0, "0", base) );
+    VERIFY( check_to_chars<unsigned long>(0, "0", base) );
+    VERIFY( check_to_chars<signed long long>(0, "0", base) );
+    VERIFY( check_to_chars<unsigned long long>(0, "0", base) );
+
+    VERIFY( check_to_chars<char>(1, "1", base) );
+    VERIFY( check_to_chars<signed char>(1, "1", base) );
+    VERIFY( check_to_chars<unsigned char>(1, "1", base) );
+    VERIFY( check_to_chars<signed short>(1, "1", base) );
+    VERIFY( check_to_chars<unsigned short>(1, "1", base) );
+    VERIFY( check_to_chars<signed int>(1, "1", base) );
+    VERIFY( check_to_chars<unsigned int>(1, "1", base) );
+    VERIFY( check_to_chars<signed long>(1, "1", base) );
+    VERIFY( check_to_chars<unsigned long>(1, "1", base) );
+    VERIFY( check_to_chars<signed long long>(1, "1", base) );
+    VERIFY( check_to_chars<unsigned long long>(1, "1", base) );
+
+    if constexpr (std::is_signed_v<char>)
+      VERIFY( check_to_chars<char>(-1, "-1", base) );
+    VERIFY( check_to_chars<signed char>(-1, "-1", base) );
+    VERIFY( check_to_chars<signed short>(-1, "-1", base) );
+    VERIFY( check_to_chars<signed int>(-1, "-1", base) );
+    VERIFY( check_to_chars<signed long>(-1, "-1", base) );
+    VERIFY( check_to_chars<signed long long>(-1, "-1", base) );
+
+    if (base > 2)
+    {
+      VERIFY( check_to_chars<char>(2, "2", base) );
+      VERIFY( check_to_chars<signed char>(2, "2", base) );
+      VERIFY( check_to_chars<unsigned char>(2, "2", base) );
+      VERIFY( check_to_chars<signed short>(2, "2", base) );
+      VERIFY( check_to_chars<unsigned short>(2, "2", base) );
+      VERIFY( check_to_chars<signed int>(2, "2", base) );
+      VERIFY( check_to_chars<unsigned int>(2, "2", base) );
+      VERIFY( check_to_chars<signed long>(2, "2", base) );
+      VERIFY( check_to_chars<unsigned long>(2, "2", base) );
+      VERIFY( check_to_chars<signed long long>(2, "2", base) );
+      VERIFY( check_to_chars<unsigned long long>(2, "2", base) );
+
+      if constexpr (std::is_signed_v<char>)
+	VERIFY( check_to_chars<char>(-2, "-2", base) );
+      VERIFY( check_to_chars<signed char>(-2, "-2", base) );
+      VERIFY( check_to_chars<signed short>(-2, "-2", base) );
+      VERIFY( check_to_chars<signed int>(-2, "-2", base) );
+      VERIFY( check_to_chars<signed long>(-2, "-2", base) );
+      VERIFY( check_to_chars<signed long long>(-2, "-2", base) );
+    }
+
+    VERIFY( check_to_chars(2017u, str2017[base]+1, base) );
+    VERIFY( check_to_chars(2017, str2017[base]+1, base) );
+    VERIFY( check_to_chars(-2017, str2017[base], base) );
+    VERIFY( check_to_chars(12345u, str12345[base]+1, base) );
+    VERIFY( check_to_chars(12345, str12345[base]+1, base) );
+    VERIFY( check_to_chars(-12345, str12345[base], base) );
+    VERIFY( check_to_chars(23456u, str23456[base]+1, base) );
+    VERIFY( check_to_chars(23456, str23456[base]+1, base) );
+    VERIFY( check_to_chars(-23456, str23456[base], base) );
+    VERIFY( check_to_chars(INT_MAX + 1ull, strINT_MIN[base]+1, base) );
+    VERIFY( check_to_chars(INT_MAX + 1ll, strINT_MIN[base]+1, base) );
+    VERIFY( check_to_chars(INT_MIN, strINT_MIN[base], base) );
+  }
+
+  VERIFY( check_to_chars(1155, "xx", 34) );
+  VERIFY( check_to_chars(1224, "yy", 35) );
+  VERIFY( check_to_chars(1295, "zz", 36) );
+}
+
+#include <sstream>
+#include <ios>
+
+// base 8
+void
+test04()
+{
+  auto to_string = [](auto val) {
+    std::ostringstream ss;
+    ss << std::oct;
+    if (val < 0)
+      ss << '-' << (~val + 1ull);
+    else if (sizeof(val) == 1)
+      ss << (int)val;
+    else
+      ss << val;
+    return ss.str();
+  };
+
+  VERIFY( check_to_chars<char>(123, to_string(123), 8) );
+  VERIFY( check_to_chars<signed char>(123, to_string(123), 8) );
+  VERIFY( check_to_chars<unsigned char>(123, to_string(123), 8) );
+  VERIFY( check_to_chars<signed short>(123, to_string(123), 8) );
+  VERIFY( check_to_chars<unsigned short>(123, to_string(123), 8) );
+  VERIFY( check_to_chars<signed int>(123, to_string(123), 8) );
+  VERIFY( check_to_chars<unsigned int>(123, to_string(123), 8) );
+  VERIFY( check_to_chars<signed long>(123, to_string(123), 8) );
+  VERIFY( check_to_chars<unsigned long>(123, to_string(123), 8) );
+  VERIFY( check_to_chars<signed long long>(123, to_string(123), 8) );
+  VERIFY( check_to_chars<unsigned long long>(123, to_string(123), 8) );
+
+  if constexpr (std::is_signed_v<char>)
+    VERIFY( check_to_chars<char>(-79, to_string(-79), 8) );
+  VERIFY( check_to_chars<signed char>(-79, to_string(-79), 8) );
+  VERIFY( check_to_chars<signed short>(-79, to_string(-79), 8) );
+  VERIFY( check_to_chars<signed int>(-79, to_string(-79), 8) );
+  VERIFY( check_to_chars<signed long>(-79, to_string(-79), 8) );
+  VERIFY( check_to_chars<signed long long>(-79, to_string(-79), 8) );
+
+  VERIFY( check_to_chars<char>(CHAR_MAX, to_string(CHAR_MAX), 8) );
+  VERIFY( check_to_chars<signed char>(SCHAR_MAX, to_string(SCHAR_MAX), 8) );
+  VERIFY( check_to_chars<unsigned char>(UCHAR_MAX, to_string(UCHAR_MAX), 8) );
+  VERIFY( check_to_chars<signed short>(SHRT_MAX, to_string(SHRT_MAX), 8) );
+  VERIFY( check_to_chars<unsigned short>(USHRT_MAX, to_string(USHRT_MAX), 8) );
+  VERIFY( check_to_chars<signed int>(INT_MAX, to_string(INT_MAX), 8) );
+  VERIFY( check_to_chars<unsigned int>(UINT_MAX, to_string(UINT_MAX), 8) );
+  VERIFY( check_to_chars<signed long>(LONG_MAX, to_string(LONG_MAX), 8) );
+  VERIFY( check_to_chars<unsigned long>(ULONG_MAX, to_string(ULONG_MAX), 8) );
+  VERIFY( check_to_chars<signed long long>(LLONG_MAX, to_string(LLONG_MAX), 8) );
+  VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX, to_string(ULLONG_MAX), 8) );
+
+  VERIFY( check_to_chars<char>(CHAR_MIN, to_string(CHAR_MIN), 8) );
+  VERIFY( check_to_chars<signed char>(SCHAR_MIN, to_string(SCHAR_MIN), 8) );
+  VERIFY( check_to_chars<signed short>(SHRT_MIN, to_string(SHRT_MIN), 8) );
+  VERIFY( check_to_chars<signed int>(INT_MIN, to_string(INT_MIN), 8) );
+  VERIFY( check_to_chars<signed long>(LONG_MIN, to_string(LONG_MIN), 8) );
+  VERIFY( check_to_chars<signed long long>(LLONG_MIN, to_string(LLONG_MIN), 8) );
+
+  VERIFY( check_to_chars<char>(CHAR_MAX/2, to_string(CHAR_MAX/2), 8) );
+  VERIFY( check_to_chars<signed char>(SCHAR_MAX/2, to_string(SCHAR_MAX/2), 8) );
+  VERIFY( check_to_chars<unsigned char>(UCHAR_MAX/2, to_string(UCHAR_MAX/2), 8) );
+  VERIFY( check_to_chars<signed short>(SHRT_MAX/2, to_string(SHRT_MAX/2), 8) );
+  VERIFY( check_to_chars<unsigned short>(USHRT_MAX/2, to_string(USHRT_MAX/2), 8) );
+  VERIFY( check_to_chars<signed int>(INT_MAX/2, to_string(INT_MAX/2), 8) );
+  VERIFY( check_to_chars<unsigned int>(UINT_MAX/2, to_string(UINT_MAX/2), 8) );
+  VERIFY( check_to_chars<signed long>(LONG_MAX/2, to_string(LONG_MAX/2), 8) );
+  VERIFY( check_to_chars<unsigned long>(ULONG_MAX/2, to_string(ULONG_MAX/2), 8) );
+  VERIFY( check_to_chars<signed long long>(LLONG_MAX/2, to_string(LLONG_MAX/2), 8) );
+  VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX/2, to_string(ULLONG_MAX/2), 8) );
+}
+
+// base 16
+void
+test05()
+{
+  auto to_string = [](auto val) {
+    std::ostringstream ss;
+    ss << std::hex;
+    if (val < 0)
+      ss << '-' << (~val + 1ull);
+    else if (sizeof(val) == 1)
+      ss << (int)val;
+    else
+      ss << val;
+    return ss.str();
+  };
+
+  VERIFY( check_to_chars<char>(123, to_string(123), 16) );
+  VERIFY( check_to_chars<signed char>(123, to_string(123), 16) );
+  VERIFY( check_to_chars<unsigned char>(123, to_string(123), 16) );
+  VERIFY( check_to_chars<signed short>(123, to_string(123), 16) );
+  VERIFY( check_to_chars<unsigned short>(123, to_string(123), 16) );
+  VERIFY( check_to_chars<signed int>(123, to_string(123), 16) );
+  VERIFY( check_to_chars<unsigned int>(123, to_string(123), 16) );
+  VERIFY( check_to_chars<signed long>(123, to_string(123), 16) );
+  VERIFY( check_to_chars<unsigned long>(123, to_string(123), 16) );
+  VERIFY( check_to_chars<signed long long>(123, to_string(123), 16) );
+  VERIFY( check_to_chars<unsigned long long>(123, to_string(123), 16) );
+
+  if constexpr (std::is_signed_v<char>)
+    VERIFY( check_to_chars<char>(-79, to_string(-79), 16) );
+  VERIFY( check_to_chars<signed char>(-79, to_string(-79), 16) );
+  VERIFY( check_to_chars<signed short>(-79, to_string(-79), 16) );
+  VERIFY( check_to_chars<signed int>(-79, to_string(-79), 16) );
+  VERIFY( check_to_chars<signed long>(-79, to_string(-79), 16) );
+  VERIFY( check_to_chars<signed long long>(-79, to_string(-79), 16) );
+
+  VERIFY( check_to_chars<char>(CHAR_MAX, to_string(CHAR_MAX), 16) );
+  VERIFY( check_to_chars<signed char>(SCHAR_MAX, to_string(SCHAR_MAX), 16) );
+  VERIFY( check_to_chars<unsigned char>(UCHAR_MAX, to_string(UCHAR_MAX), 16) );
+  VERIFY( check_to_chars<signed short>(SHRT_MAX, to_string(SHRT_MAX), 16) );
+  VERIFY( check_to_chars<unsigned short>(USHRT_MAX, to_string(USHRT_MAX), 16) );
+  VERIFY( check_to_chars<signed int>(INT_MAX, to_string(INT_MAX), 16) );
+  VERIFY( check_to_chars<unsigned int>(UINT_MAX, to_string(UINT_MAX), 16) );
+  VERIFY( check_to_chars<signed long>(LONG_MAX, to_string(LONG_MAX), 16) );
+  VERIFY( check_to_chars<unsigned long>(ULONG_MAX, to_string(ULONG_MAX), 16) );
+  VERIFY( check_to_chars<signed long long>(LLONG_MAX, to_string(LLONG_MAX), 16) );
+  VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX, to_string(ULLONG_MAX), 16) );
+
+  VERIFY( check_to_chars<char>(CHAR_MIN, to_string(CHAR_MIN), 16) );
+  VERIFY( check_to_chars<signed char>(SCHAR_MIN, to_string(SCHAR_MIN), 16) );
+  VERIFY( check_to_chars<signed short>(SHRT_MIN, to_string(SHRT_MIN), 16) );
+  VERIFY( check_to_chars<signed int>(INT_MIN, to_string(INT_MIN), 16) );
+  VERIFY( check_to_chars<signed long>(LONG_MIN, to_string(LONG_MIN), 16) );
+  VERIFY( check_to_chars<signed long long>(LLONG_MIN, to_string(LLONG_MIN), 16) );
+
+  VERIFY( check_to_chars<char>(CHAR_MAX/2, to_string(CHAR_MAX/2), 16) );
+  VERIFY( check_to_chars<signed char>(SCHAR_MAX/2, to_string(SCHAR_MAX/2), 16) );
+  VERIFY( check_to_chars<unsigned char>(UCHAR_MAX/2, to_string(UCHAR_MAX/2), 16) );
+  VERIFY( check_to_chars<signed short>(SHRT_MAX/2, to_string(SHRT_MAX/2), 16) );
+  VERIFY( check_to_chars<unsigned short>(USHRT_MAX/2, to_string(USHRT_MAX/2), 16) );
+  VERIFY( check_to_chars<signed int>(INT_MAX/2, to_string(INT_MAX/2), 16) );
+  VERIFY( check_to_chars<unsigned int>(UINT_MAX/2, to_string(UINT_MAX/2), 16) );
+  VERIFY( check_to_chars<signed long>(LONG_MAX/2, to_string(LONG_MAX/2), 16) );
+  VERIFY( check_to_chars<unsigned long>(ULONG_MAX/2, to_string(ULONG_MAX/2), 16) );
+  VERIFY( check_to_chars<signed long long>(LLONG_MAX/2, to_string(LLONG_MAX/2), 16) );
+  VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX/2, to_string(ULLONG_MAX/2), 16) );
+}
+
+#include <bitset>
+
+// base 2
+void
+test06()
+{
+  auto to_string = [](auto val) {
+    std::string s, sign;
+    if (val < 0)
+    {
+      auto absval = ~val + 1ull;
+      s = std::bitset<sizeof(absval) * CHAR_BIT>(absval).to_string();
+      sign = '-';
+    }
+    else
+      s = std::bitset<sizeof(val) * CHAR_BIT>(val).to_string();
+    auto pos = s.find_first_not_of("0");
+    if (pos == std::string::npos)
+      s.resize(1);
+    else
+      s.erase(0, pos);
+    return sign + s;
+  };
+
+  VERIFY( check_to_chars<char>(123, to_string(123), 2) );
+  VERIFY( check_to_chars<signed char>(123, to_string(123), 2) );
+  VERIFY( check_to_chars<unsigned char>(123, to_string(123), 2) );
+  VERIFY( check_to_chars<signed short>(123, to_string(123), 2) );
+  VERIFY( check_to_chars<unsigned short>(123, to_string(123), 2) );
+  VERIFY( check_to_chars<signed int>(123, to_string(123), 2) );
+  VERIFY( check_to_chars<unsigned int>(123, to_string(123), 2) );
+  VERIFY( check_to_chars<signed long>(123, to_string(123), 2) );
+  VERIFY( check_to_chars<unsigned long>(123, to_string(123), 2) );
+  VERIFY( check_to_chars<signed long long>(123, to_string(123), 2) );
+  VERIFY( check_to_chars<unsigned long long>(123, to_string(123), 2) );
+
+  if constexpr (std::is_signed_v<char>)
+    VERIFY( check_to_chars<char>(-79, to_string(-79), 2) );
+  VERIFY( check_to_chars<signed char>(-79, to_string(-79), 2) );
+  VERIFY( check_to_chars<signed short>(-79, to_string(-79), 2) );
+  VERIFY( check_to_chars<signed int>(-79, to_string(-79), 2) );
+  VERIFY( check_to_chars<signed long>(-79, to_string(-79), 2) );
+  VERIFY( check_to_chars<signed long long>(-79, to_string(-79), 2) );
+
+  VERIFY( check_to_chars<char>(CHAR_MAX, to_string(CHAR_MAX), 2) );
+  VERIFY( check_to_chars<signed char>(SCHAR_MAX, to_string(SCHAR_MAX), 2) );
+  VERIFY( check_to_chars<unsigned char>(UCHAR_MAX, to_string(UCHAR_MAX), 2) );
+  VERIFY( check_to_chars<signed short>(SHRT_MAX, to_string(SHRT_MAX), 2) );
+  VERIFY( check_to_chars<unsigned short>(USHRT_MAX, to_string(USHRT_MAX), 2) );
+  VERIFY( check_to_chars<signed int>(INT_MAX, to_string(INT_MAX), 2) );
+  VERIFY( check_to_chars<unsigned int>(UINT_MAX, to_string(UINT_MAX), 2) );
+  VERIFY( check_to_chars<signed long>(LONG_MAX, to_string(LONG_MAX), 2) );
+  VERIFY( check_to_chars<unsigned long>(ULONG_MAX, to_string(ULONG_MAX), 2) );
+  VERIFY( check_to_chars<signed long long>(LLONG_MAX, to_string(LLONG_MAX), 2) );
+  VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX, to_string(ULLONG_MAX), 2) );
+
+  VERIFY( check_to_chars<char>(CHAR_MIN, to_string(CHAR_MIN), 2) );
+  VERIFY( check_to_chars<signed char>(SCHAR_MIN, to_string(SCHAR_MIN), 2) );
+  VERIFY( check_to_chars<signed short>(SHRT_MIN, to_string(SHRT_MIN), 2) );
+  VERIFY( check_to_chars<signed int>(INT_MIN, to_string(INT_MIN), 2) );
+  VERIFY( check_to_chars<signed long>(LONG_MIN, to_string(LONG_MIN), 2) );
+  VERIFY( check_to_chars<signed long long>(LLONG_MIN, to_string(LLONG_MIN), 2) );
+
+  VERIFY( check_to_chars<char>(CHAR_MAX/2, to_string(CHAR_MAX/2), 2) );
+  VERIFY( check_to_chars<signed char>(SCHAR_MAX/2, to_string(SCHAR_MAX/2), 2) );
+  VERIFY( check_to_chars<unsigned char>(UCHAR_MAX/2, to_string(UCHAR_MAX/2), 2) );
+  VERIFY( check_to_chars<signed short>(SHRT_MAX/2, to_string(SHRT_MAX/2), 2) );
+  VERIFY( check_to_chars<unsigned short>(USHRT_MAX/2, to_string(USHRT_MAX/2), 2) );
+  VERIFY( check_to_chars<signed int>(INT_MAX/2, to_string(INT_MAX/2), 2) );
+  VERIFY( check_to_chars<unsigned int>(UINT_MAX/2, to_string(UINT_MAX/2), 2) );
+  VERIFY( check_to_chars<signed long>(LONG_MAX/2, to_string(LONG_MAX/2), 2) );
+  VERIFY( check_to_chars<unsigned long>(ULONG_MAX/2, to_string(ULONG_MAX/2), 2) );
+  VERIFY( check_to_chars<signed long long>(LLONG_MAX/2, to_string(LLONG_MAX/2), 2) );
+  VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX/2, to_string(ULLONG_MAX/2), 2) );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+  test05();
+  test06();
+}
diff --git a/libstdc++-v3/testsuite/20_util/to_chars/1_neg.cc b/libstdc++-v3/testsuite/20_util/to_chars/1_neg.cc
new file mode 100644
index 0000000..b5cd10b
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/to_chars/1_neg.cc
@@ -0,0 +1,35 @@
+// Copyright (C) 2017 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++1z } }
+
+#include <utility>
+
+void
+test01(char* first, char* last)
+{
+#if _GLIBCXX_USE_WCHAR_T
+  std::to_chars(first, last, L'\x1'); // { dg-error "no matching" }
+  std::to_chars(first, last, L'\x1', 10); // { dg-error "no matching" }
+#endif
+
+  std::to_chars(first, last, u'\x1'); // { dg-error "no matching" }
+  std::to_chars(first, last, u'\x1', 10); // { dg-error "no matching" }
+  std::to_chars(first, last, U'\x1'); // { dg-error "no matching" }
+  std::to_chars(first, last, U'\x1', 10); // { dg-error "no matching" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/to_chars/2.cc b/libstdc++-v3/testsuite/20_util/to_chars/2.cc
new file mode 100644
index 0000000..066622c
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/to_chars/2.cc
@@ -0,0 +1,69 @@
+// Copyright (C) 2017 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++1z } }
+
+#include <utility>
+#include <testsuite_hooks.h>
+
+// Test std::to_chars error handling.
+
+void
+test01()
+{
+  char buf[9] = "********";
+  std::to_chars_result r;
+
+  r = std::to_chars(buf, buf, 1);
+  VERIFY( r.ec == std::errc::value_too_large );
+  VERIFY( r.ptr == buf );
+  VERIFY( *r.ptr == '*' );
+
+  r = std::to_chars(buf, buf + 3, 0b1000, 2);
+  VERIFY( r.ec == std::errc::value_too_large );
+  VERIFY( r.ptr == buf + 3 );
+  VERIFY( *r.ptr == '*' );
+  r = std::to_chars(buf, buf + 4, 0b1000, 2);
+  VERIFY( !r.ec );
+  VERIFY( r.ptr == buf + 4 );
+  VERIFY( *r.ptr == '*' );
+
+  r = std::to_chars(buf, buf + 4, 10000, 10);
+  VERIFY( r.ec == std::errc::value_too_large );
+  VERIFY( r.ptr == buf + 4 );
+  VERIFY( *r.ptr == '*' );
+  r = std::to_chars(buf, buf + 5, 10000, 10);
+  VERIFY( !r.ec );
+  VERIFY( r.ptr == buf + 5 );
+  VERIFY( *r.ptr == '*' );
+
+  r = std::to_chars(buf, buf + 5, 0x100000, 16);
+  VERIFY( r.ec == std::errc::value_too_large );
+  VERIFY( r.ptr == buf + 5 );
+  VERIFY( *r.ptr == '*' );
+  r = std::to_chars(buf, buf + 6, 0x100000, 16);
+  VERIFY( !r.ec );
+  VERIFY( r.ptr == buf + 6 );
+  VERIFY( *r.ptr == '*' );
+}
+
+int
+main()
+{
+  test01();
+}
diff --git a/libstdc++-v3/testsuite/20_util/to_chars/requirements.cc b/libstdc++-v3/testsuite/20_util/to_chars/requirements.cc
new file mode 100644
index 0000000..632bc81
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/to_chars/requirements.cc
@@ -0,0 +1,49 @@
+// Copyright (C) 2017 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/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++1z } }
+
+#include <utility>
+
+namespace std
+{
+  struct to_chars_result;
+
+  char* to_chars_result::*pm2 = &to_chars_result::ptr;
+  error_code to_chars_result::*pm1 = &to_chars_result::ec;
+
+  to_chars_result (*f1)(char*, char*, char, int) = &to_chars;
+  to_chars_result (*f2)(char*, char*, signed char, int) = &to_chars;
+  to_chars_result (*f3)(char*, char*, unsigned char, int) = &to_chars;
+  to_chars_result (*f4)(char*, char*, signed short, int) = &to_chars;
+  to_chars_result (*f5)(char*, char*, unsigned short, int) = &to_chars;
+  to_chars_result (*f6)(char*, char*, signed int, int) = &to_chars;
+  to_chars_result (*f7)(char*, char*, unsigned int, int) = &to_chars;
+  to_chars_result (*f8)(char*, char*, signed long, int) = &to_chars;
+  to_chars_result (*f9)(char*, char*, unsigned long, int) = &to_chars;
+  to_chars_result (*f10)(char*, char*, signed long long, int) = &to_chars;
+  to_chars_result (*f11)(char*, char*, unsigned long long, int) = &to_chars;
+}
+
+void bind()
+{
+  char buf[1];
+  auto [p, e] = std::to_chars(buf, buf + 1, 1, 10);
+  char** pa = std::addressof(p);
+  std::error_code* ea = std::addressof(e);
+}

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] Define std::to_chars and std::from_chars for C++17 (P0067R5, partial)
  2017-04-07 12:29 [PATCH] Define std::to_chars and std::from_chars for C++17 (P0067R5, partial) Jonathan Wakely
@ 2017-04-10 13:07 ` Jonathan Wakely
  0 siblings, 0 replies; 4+ messages in thread
From: Jonathan Wakely @ 2017-04-10 13:07 UTC (permalink / raw)
  To: libstdc++, gcc-patches

On 07/04/17 13:29 +0100, Jonathan Wakely wrote:
>This adds another piece of the C++17 library, the std::to_chars and
>std::from_chars functions for converting numbers to/from strings. This
>only adds the integer support, floating point types will require a lot
>more work.
>
>This has only been lightly optimised, so it beats printf on average,
>but there's probably more opportunity for improvement. I didn't
>investigate whether doing all work with unsigned long long would be
>faster, instead of using function templates specialized for unsigned
>int, unsigned long and unsigned long long. It should help code size,
>but I don't know if it would be faster. I also didn't investigate
>whether doing from_chars in two stages would be better, i.e. finding
>all the characters that are valid digits in the given base first, and
>then converting them to an integer in a second step. I'm sure there's
>lots of tuning that could be done, but I hope this is good enough to
>start with.

I forgot to say that most of the optimisations I did include come from
a talk by Andrei Alexandrescu:

https://www.slideshare.net/andreialexandrescu1/three-optimization-tips-for-c
https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920

Whether these actually help might be debatable. I think I did test all
of them against the simpler code before including them.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] Define std::to_chars and std::from_chars for C++17 (P0067R5, partial)
  2017-04-16 19:33 Luc Danton
@ 2017-04-16 20:13 ` Jonathan Wakely
  0 siblings, 0 replies; 4+ messages in thread
From: Jonathan Wakely @ 2017-04-16 20:13 UTC (permalink / raw)
  To: Luc Danton; +Cc: libstdc++, gcc-patches

On 16 April 2017 at 19:16, Luc Danton wrote:
> On 07/04/17 13:29 +0100, Jonathan Wakely wrote:
>>
>> +             constexpr char __abc[] = "abcdefghijklmnopqrstuvwxyz";
>> +             unsigned char __lc = std::tolower(__c);
>> +             constexpr bool __consecutive = __consecutive_chars(__abc,
>> 26);
>> +             if _GLIBCXX17_CONSTEXPR (__consecutive)
>> +               {
>> +                 // Characters 'a'..'z' are consecutive
>> +                 if (std::isalpha(__c) && (__lc - 'a') < __b)
>> +                   __c = __lc - 'a' + 10;
>
> <snip>
>
> Is that alright? I have my eyes set on the following line in particular:
>
>> +             unsigned char __lc = std::tolower(__c);
>
>
> Correct me if I'm wrong but that's locale sensitive. As it turns out in
> a Turkish locale the lowercase for <I> is <ı> "U+0131 LATIN SMALL LETTER
> DOTLESS I".

Good catch, thanks.

>
> I installed a Turkish locale on an old system of mine (Linux, UTF-8) and
> sketched out the lines to quickly test the logic. As best as I can tell
> the following happens when the global locale is set to Turkish:
>
>  - __lc is 'I' unchanged because <ı> U+0131 would encode to two UTF-8
>    codepoints aka can't fit in a char
>  - the test succeeds
>  - the computed value that ends up being written to __c is decimal -14
>
> Keep in mind I didn't run the actual code from the patch, so I may have
> got something wrong. Still, the Turkish i/İ and ı/I pairs are just one
> example in one locale. Are std::tolower and std::isalpha the right tools
> for this job? (These are the only two locale sensitive parts I
> noticed in the code.)

Yeah, I'll avoid isalpha and tolower.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] Define std::to_chars and std::from_chars for C++17 (P0067R5, partial)
@ 2017-04-16 19:33 Luc Danton
  2017-04-16 20:13 ` Jonathan Wakely
  0 siblings, 1 reply; 4+ messages in thread
From: Luc Danton @ 2017-04-16 19:33 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches

On 07/04/17 13:29 +0100, Jonathan Wakely wrote:
> +	      constexpr char __abc[] = "abcdefghijklmnopqrstuvwxyz";
> +	      unsigned char __lc = std::tolower(__c);
> +	      constexpr bool __consecutive = __consecutive_chars(__abc, 26);
> +	      if _GLIBCXX17_CONSTEXPR (__consecutive)
> +		{
> +		  // Characters 'a'..'z' are consecutive
> +		  if (std::isalpha(__c) && (__lc - 'a') < __b)
> +		    __c = __lc - 'a' + 10;
<snip>

Is that alright? I have my eyes set on the following line in particular:

> +	      unsigned char __lc = std::tolower(__c);

Correct me if I'm wrong but that's locale sensitive. As it turns out in
a Turkish locale the lowercase for <I> is <ı> "U+0131 LATIN SMALL LETTER
DOTLESS I".

I installed a Turkish locale on an old system of mine (Linux, UTF-8) and
sketched out the lines to quickly test the logic. As best as I can tell
the following happens when the global locale is set to Turkish:

  - __lc is 'I' unchanged because <ı> U+0131 would encode to two UTF-8
    codepoints aka can't fit in a char
  - the test succeeds
  - the computed value that ends up being written to __c is decimal -14

Keep in mind I didn't run the actual code from the patch, so I may have
got something wrong. Still, the Turkish i/İ and ı/I pairs are just one
example in one locale. Are std::tolower and std::isalpha the right tools
for this job? (These are the only two locale sensitive parts I
noticed in the code.)

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2017-04-16 19:33 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-07 12:29 [PATCH] Define std::to_chars and std::from_chars for C++17 (P0067R5, partial) Jonathan Wakely
2017-04-10 13:07 ` Jonathan Wakely
2017-04-16 19:33 Luc Danton
2017-04-16 20:13 ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).