aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/testsuite/21_strings
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2023-08-16 16:55:00 +0100
committerJonathan Wakely <jwakely@redhat.com>2023-08-17 20:24:17 +0100
commitaeed687f4e08f1364ab60882a012fe740e05a7da (patch)
treecc479e8a6cb79a46f120000175c971d6c50fc068 /libstdc++-v3/testsuite/21_strings
parent51ec07b116b802d845d762beddf8b98e8c0e32ab (diff)
downloadgcc-aeed687f4e08f1364ab60882a012fe740e05a7da.zip
gcc-aeed687f4e08f1364ab60882a012fe740e05a7da.tar.gz
gcc-aeed687f4e08f1364ab60882a012fe740e05a7da.tar.bz2
libstdc++: Implement std::to_string in terms of std::format (P2587R3)
This change for C++26 affects std::to_string for floating-point arguments, so that they should be formatted using std::format("{}", v) instead of using sprintf. The modified specification in the standard also affects integral arguments, but there's no observable difference for them, and we already use std::to_chars for them anyway. To avoid <string> depending on all of <format>, this change actually just uses std::to_chars directly instead of using std::format. This is equivalent, because the format spec "{}" doesn't use any of the other features of std::format. libstdc++-v3/ChangeLog: * include/bits/basic_string.h (to_string(floating-point-type)): Implement using std::to_chars for C++26. * include/bits/version.def (__cpp_lib_to_string): Define. * include/bits/version.h: Regenerate. * testsuite/21_strings/basic_string/numeric_conversions/char/dr1261.cc: Adjust expected result in C++26 mode. * testsuite/21_strings/basic_string/numeric_conversions/char/to_string.cc: Likewise. * testsuite/21_strings/basic_string/numeric_conversions/wchar_t/dr1261.cc: Likewise. * testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring.cc: Likewise. * testsuite/21_strings/basic_string/numeric_conversions/char/to_string_float.cc: New test. * testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_float.cc: New test. * testsuite/21_strings/basic_string/numeric_conversions/version.cc: New test.
Diffstat (limited to 'libstdc++-v3/testsuite/21_strings')
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/dr1261.cc11
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string.cc9
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_float.cc148
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/version.cc18
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/dr1261.cc11
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring.cc9
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_float.cc145
7 files changed, 341 insertions, 10 deletions
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/dr1261.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/dr1261.cc
index 49998b5..b952c26 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/dr1261.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/dr1261.cc
@@ -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()
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string.cc
index dc7b87b..c770b4f 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string.cc
@@ -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()
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_float.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_float.cc
new file mode 100644
index 0000000..3837c89
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/char/to_string_float.cc
@@ -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();
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/version.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/version.cc
new file mode 100644
index 0000000..630e06f
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/version.cc
@@ -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
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/dr1261.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/dr1261.cc
index 8dbdd7b..c2b36fd 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/dr1261.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/dr1261.cc
@@ -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()
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring.cc
index dbfb639..6698783 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring.cc
@@ -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
}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_float.cc b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_float.cc
new file mode 100644
index 0000000..83f5bb1
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/numeric_conversions/wchar_t/to_wstring_float.cc
@@ -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();
+}