@@ -47,9 +47,14 @@
# include <string_view>
#endif
+#if __cplusplus > 202302L
+# include <charconv>
+#endif
+
#define __glibcxx_want_constexpr_string
#define __glibcxx_want_string_resize_and_overwrite
#define __glibcxx_want_string_udls
+#define __glibcxx_want_to_string
#include <bits/version.h>
#if ! _GLIBCXX_USE_CXX11_ABI
@@ -4185,6 +4190,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
{ return std::stod(__str, __idx); }
#endif
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 1261. Insufficent overloads for to_string / to_wstring
_GLIBCXX_NODISCARD
@@ -4287,7 +4293,65 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
return __str;
}
-#if _GLIBCXX_USE_C99_STDIO
+#if __cpp_lib_to_string >= 202306L
+
+ [[nodiscard]]
+ inline string
+ to_string(float __val)
+ {
+ string __str;
+ size_t __len = 15;
+ do {
+ __str.resize_and_overwrite(__len,
+ [__val, &__len] (char* __p, size_t __n) {
+ auto [__end, __err] = std::to_chars(__p, __p + __n, __val);
+ if (__err == errc{}) [[likely]]
+ return __end - __p;
+ __len *= 2;
+ return __p - __p;;
+ });
+ } while (__str.empty());
+ return __str;
+ }
+
+ [[nodiscard]]
+ inline string
+ to_string(double __val)
+ {
+ string __str;
+ size_t __len = 15;
+ do {
+ __str.resize_and_overwrite(__len,
+ [__val, &__len] (char* __p, size_t __n) {
+ auto [__end, __err] = std::to_chars(__p, __p + __n, __val);
+ if (__err == errc{}) [[likely]]
+ return __end - __p;
+ __len *= 2;
+ return __p - __p;;
+ });
+ } while (__str.empty());
+ return __str;
+ }
+
+ [[nodiscard]]
+ inline string
+ to_string(long double __val)
+ {
+ string __str;
+ size_t __len = 15;
+ do {
+ __str.resize_and_overwrite(__len,
+ [__val, &__len] (char* __p, size_t __n) {
+ auto [__end, __err] = std::to_chars(__p, __p + __n, __val);
+ if (__err == errc{}) [[likely]]
+ return __end - __p;
+ __len *= 2;
+ return __p - __p;;
+ });
+ } while (__str.empty());
+ return __str;
+ }
+#elif _GLIBCXX_USE_C99_STDIO
// NB: (v)snprintf vs sprintf.
_GLIBCXX_NODISCARD
@@ -4465,7 +4529,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
to_wstring(unsigned long long __val)
{ return std::__to_wstring_numeric(std::to_string(__val)); }
-#if _GLIBCXX_USE_C99_STDIO
+#if __cpp_lib_to_string || _GLIBCXX_USE_C99_STDIO
_GLIBCXX_NODISCARD
inline wstring
to_wstring(float __val)
@@ -1582,6 +1582,16 @@ ftms = {
};
};
+ftms = {
+ name = to_string;
+ values = {
+ v = 202306;
+ cxxmin = 26;
+ hosted = yes;
+ extra_cond = "__glibcxx_to_chars";
+ };
+};
+
// Standard test specifications.
stds[97] = ">= 199711L";
stds[03] = ">= 199711L";
@@ -1590,6 +1600,7 @@ stds[14] = ">= 201402L";
stds[17] = ">= 201703L";
stds[20] = ">= 202002L";
stds[23] = ">= 202302L";
+stds[26] = "> 202302L"; // TODO: update when finalized
// Local Variables:
// compile-command: "autogen version.def"
@@ -1939,4 +1939,15 @@
#endif /* !defined(__cpp_lib_string_resize_and_overwrite) && defined(__glibcxx_want_string_resize_and_overwrite) */
#undef __glibcxx_want_string_resize_and_overwrite
+// from version.def line 1586
+#if !defined(__cpp_lib_to_string)
+# if (__cplusplus > 202302L) && _GLIBCXX_HOSTED && (__glibcxx_to_chars)
+# define __glibcxx_to_string 202306L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_to_string)
+# define __cpp_lib_to_string 202306L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_to_string) && defined(__glibcxx_want_to_string) */
+#undef __glibcxx_want_to_string
+
#undef __glibcxx_want_all
@@ -46,14 +46,19 @@ void test01()
const string six(to_string(400ull));
VERIFY( six == "400" );
+ string tail;
+#if __cpp_lib_to_string < 202306L
+ tail = ".000000";
+#endif
+
const string seven(to_string(-1.0F));
- VERIFY( seven == "-1.000000" );
+ VERIFY( seven == "-1" + tail );
const string eight(to_string(2.0));
- VERIFY( eight == "2.000000" );
+ VERIFY( eight == "2" + tail );
const string nine(to_string(-4.0L));
- VERIFY( nine == "-4.000000" );
+ VERIFY( nine == "-4" + tail );
}
int main()
@@ -46,13 +46,18 @@ test01()
string four(to_string(ull2));
VERIFY( four == "3000" );
+ string tail;
+#if __cpp_lib_to_string < 202306L
+ tail = ".000000";
+#endif
+
long double ld1 = 2.0L;
string five(to_string(ld1));
- VERIFY( five == "2.000000" );
+ VERIFY( five == "2" + tail );
long double ld2 = -4.0L;
string six(to_string(ld2));
- VERIFY( six == "-4.000000" );
+ VERIFY( six == "-4" + tail );
}
int main()
new file mode 100644
@@ -0,0 +1,148 @@
+// { dg-do run { target c++11 } }
+// { dg-require-namedlocale "de_DE.ISO8859-15" }
+
+// C++11 21.5 Numeric Conversions [string.conversions]
+
+#include <string>
+#include <format>
+#include <limits>
+#include <locale>
+#include <cstdio>
+#include <testsuite_hooks.h>
+
+namespace test
+{
+// Canonical version of std::to_string(double) as specified in the standard.
+
+#if __cplusplus > 202302L
+
+#ifndef __cpp_lib_to_string
+# error "Feature-test macro for std::to_string missing in <string>"
+#elif __cpp_lib_to_string != 202306L
+# error "Feature-test macro for std::to_string has wrong value in <string>"
+#endif
+
+static std::string to_string(float val) { return std::format("{}", val); }
+static std::string to_string(double val) { return std::format("{}", val); }
+static std::string to_string(long double val) { return std::format("{}", val); }
+
+#else
+
+#ifdef __cpp_lib_to_string
+# error "__cpp_lib_to_string should not be defined for C++23"
+#endif
+
+static std::string to_string(double val)
+{
+ std::string str(100, '9');
+retry:
+ const int size = str.size();
+ const int len = std::snprintf(&str[0], size + 1, "%f", val);
+ str.resize(len);
+ if (len > size)
+ goto retry;
+ return str;
+}
+
+// snprintf promotes float to double
+static std::string to_string(float val) { return to_string((double)val); }
+
+static std::string to_string(long double val)
+{
+ std::string str(100, '9');
+retry:
+ const int size = str.size();
+ const int len = std::snprintf(&str[0], size + 1, "%Lf", val);
+ str.resize(len);
+ if (len > size)
+ goto retry;
+ return str;
+}
+#endif
+} // namespace test
+
+template<typename T>
+ void check_value(T val)
+ {
+ const std::string s = std::to_string(val);
+ const std::string expected = test::to_string(val);
+ VERIFY( s == expected );
+ VERIFY( s[s.size()] == '\0' ); // null-terminator not overwritten
+ }
+
+template<typename T>
+ void check_values()
+ {
+ const T values[] = {
+ 0.0, 0.0625, 0.25, 0.5, 1.25, 1e2, 1e7, 1e8, 1e-2, 1e-7, 1e-8,
+ 2e38, 4.4e+19, 6.25e-12, 7.89e+23,
+ 12345.6789, (T) 1234567890123456.e100L, (T) 1213141516e-99L,
+ std::numeric_limits<T>::min(),
+ std::numeric_limits<T>::max(),
+ std::numeric_limits<T>::epsilon(),
+ std::numeric_limits<T>::infinity(),
+ std::numeric_limits<T>::quiet_NaN(),
+ };
+
+ std::locale::global(std::locale::classic());
+
+ for (auto v : values)
+ {
+ check_value(v);
+ check_value(-v);
+ }
+
+ std::locale::global(std::locale(ISO_8859(15,de_DE)));
+
+ for (auto v : values)
+ {
+ check_value(v);
+ check_value(-v);
+ }
+
+ std::locale::global(std::locale::classic());
+ }
+
+void test01()
+{
+ // Examples from P2587R3 `to_string` or not `to_string`
+
+
+ VERIFY( std::to_string(42) == "42" );
+ VERIFY( std::to_string(12345) == "12345" );
+ auto max = std::to_string(1.7976931348623157e+308);
+
+#if __cplusplus <= 202302L
+ VERIFY( std::to_string(0.42) == "0.420000" );
+ VERIFY( std::to_string(1e-7) == "0.000000" );
+ VERIFY( std::to_string(-1e-7) == "-0.000000" );
+ VERIFY( max.substr(0, 17) == "17976931348623157" );
+ VERIFY( max.substr(max.size() - 7) == ".000000" );
+#else
+ VERIFY( std::to_string(0.42) == "0.42" );
+ VERIFY( std::to_string(1e-7) == "1e-07" );
+ VERIFY( std::to_string(-1e-7) == "-1e-07" );
+ VERIFY( max == "1.7976931348623157e+308" );
+#endif
+
+ std::locale::global(std::locale(ISO_8859(15,de_DE)));
+#if __cplusplus <= 202302L
+ VERIFY( std::to_string(1234.5) == "1234,500000" );
+#else
+ VERIFY( std::to_string(1234.5) == "1234.5" );
+#endif
+ std::locale::global(std::locale::classic());
+}
+
+void test02()
+{
+ check_values<float>();
+ check_values<double>();
+ check_values<long double>();
+}
+
+int main()
+{
+ test01();
+ test02();
+}
new file mode 100644
@@ -0,0 +1,18 @@
+// { dg-do compile }
+#include <version>
+
+#if __cplusplus > 202302L
+
+#ifndef __cpp_lib_to_string
+# error "Feature-test macro for std::to_string missing in <string>"
+#elif __cpp_lib_to_string != 202306L
+# error "Feature-test macro for std::to_string has wrong value in <string>"
+#endif
+
+#else
+
+#ifdef __cpp_lib_to_string
+# error "__cpp_lib_to_string should not be defined for C++23"
+#endif
+
+#endif
@@ -46,14 +46,19 @@ void test01()
const wstring six(to_wstring(400ull));
VERIFY( six == L"400" );
+ wstring tail;
+#if __cpp_lib_to_string < 202306L
+ tail = L".000000";
+#endif
+
const wstring seven(to_wstring(-1.0F));
- VERIFY( seven == L"-1.000000" );
+ VERIFY( seven == L"-1" + tail );
const wstring eight(to_wstring(2.0));
- VERIFY( eight == L"2.000000" );
+ VERIFY( eight == L"2" + tail );
const wstring nine(to_wstring(-4.0L));
- VERIFY( nine == L"-4.000000" );
+ VERIFY( nine == L"-4" + tail );
}
int main()
@@ -47,13 +47,18 @@ test01()
wstring four(to_wstring(ull2));
VERIFY( four == L"3000" );
+ wstring tail;
+#if __cpp_lib_to_string < 202306L
+ tail = L".000000";
+#endif
+
long double ld1 = 2.0L;
wstring five(to_wstring(ld1));
- VERIFY( five == L"2.000000" );
+ VERIFY( five == L"2" + tail );
long double ld2 = -4.0L;
wstring six(to_wstring(ld2));
- VERIFY( six == L"-4.000000" );
+ VERIFY( six == L"-4" + tail );
#endif
}
new file mode 100644
@@ -0,0 +1,145 @@
+// { dg-do run { target c++11 } }
+// { dg-require-namedlocale "de_DE.ISO8859-15" }
+// { dg-require-string-conversions "" }
+
+// C++11 21.5 Numeric Conversions [string.conversions]
+
+#include <string>
+#include <format>
+#include <limits>
+#include <locale>
+#include <cstdio>
+#include <testsuite_hooks.h>
+
+namespace test
+{
+// Canonical version of std::to_wstring(double) as specified in the standard.
+
+#if __cplusplus > 202302L
+
+std::wstring to_wstring(float val) { return std::format(L"{}", val); }
+std::wstring to_wstring(double val) { return std::format(L"{}", val); }
+std::wstring to_wstring(long double val) { return std::format(L"{}", val); }
+
+#else
+
+std::wstring to_wstring(double val)
+{
+ std::wstring str(100, L'9');
+retry:
+ const int size = str.size();
+ const int len = std::swprintf(&str[0], size + 1, L"%f", val);
+ if (len == -1) // N.B. swprintf just returns -1 if the buffer is too small.
+ {
+ str.resize(size * 2);
+ goto retry;
+ }
+ str.resize(len);
+ return str;
+}
+
+// snprintf promotes float to double
+std::wstring to_wstring(float val) { return to_wstring((double)val); }
+
+std::wstring to_wstring(long double val)
+{
+ std::wstring str(100, L'9');
+retry:
+ const int size = str.size();
+ const int len = std::swprintf(&str[0], size + 1, L"%Lf", val);
+ if (len == -1) // N.B. swprintf just returns -1 if the buffer is too small.
+ {
+ str.resize(size * 2);
+ goto retry;
+ }
+ str.resize(len);
+ return str;
+}
+#endif
+} // namespace test
+
+template<typename T>
+ void check_value(T val)
+ {
+ const std::wstring s = std::to_wstring(val);
+ const std::wstring expected = test::to_wstring(val);
+ VERIFY( s == expected );
+ VERIFY( s[s.size()] == L'\0' ); // null-terminator not overwritten
+ }
+
+template<typename T>
+ void check_values()
+ {
+ const T values[] = {
+ 0.0, 0.0625, 0.25, 0.5, 1.25, 1e2, 1e7, 1e8, 1e-2, 1e-7, 1e-8,
+ 2e38, 4.4e+19, 6.25e-12, 7.89e+23,
+ 12345.6789, (T) 1234567890123456.e100L, (T) 1213141516e-99L,
+ std::numeric_limits<T>::min(),
+ std::numeric_limits<T>::max(),
+ std::numeric_limits<T>::epsilon(),
+ std::numeric_limits<T>::infinity(),
+ std::numeric_limits<T>::quiet_NaN(),
+ };
+
+ std::locale::global(std::locale::classic());
+
+ for (auto v : values)
+ {
+ check_value(v);
+ check_value(-v);
+ }
+
+ std::locale::global(std::locale(ISO_8859(15,de_DE)));
+
+ for (auto v : values)
+ {
+ check_value(v);
+ check_value(-v);
+ }
+
+ std::locale::global(std::locale::classic());
+ }
+
+void test01()
+{
+ // Examples from P2587R3 `to_string` or not `to_string`
+
+
+ VERIFY( std::to_wstring(42) == L"42" );
+ VERIFY( std::to_wstring(12345) == L"12345" );
+ auto max = std::to_wstring(1.7976931348623157e+308);
+
+#if __cplusplus <= 202302L
+ VERIFY( std::to_wstring(0.42) == L"0.420000" );
+ VERIFY( std::to_wstring(1e-7) == L"0.000000" );
+ VERIFY( std::to_wstring(-1e-7) == L"-0.000000" );
+ VERIFY( max.substr(0, 17) == L"17976931348623157" );
+ VERIFY( max.substr(max.size() - 7) == L".000000" );
+#else
+ VERIFY( std::to_wstring(0.42) == L"0.42" );
+ VERIFY( std::to_wstring(1e-7) == L"1e-07" );
+ VERIFY( std::to_wstring(-1e-7) == L"-1e-07" );
+ VERIFY( max == L"1.7976931348623157e+308" );
+#endif
+
+ std::locale::global(std::locale(ISO_8859(15,de_DE)));
+#if __cplusplus <= 202302L
+ VERIFY( std::to_wstring(1234.5) == L"1234,500000" );
+#else
+ VERIFY( std::to_wstring(1234.5) == L"1234.5" );
+#endif
+ std::locale::global(std::locale::classic());
+}
+
+void test02()
+{
+ check_values<float>();
+ check_values<double>();
+ check_values<long double>();
+}
+
+int main()
+{
+ test01();
+ test02();
+}