Skip to content

Commit 607f643

Browse files
committed
[libc++][string] P2587R3: to_string or not to_string
Implements: https://wg21.link/P2587R3 - https://eel.is/c++draft/string.conversions - https://eel.is/c++draft/string.classes
1 parent 7f1d757 commit 607f643

File tree

9 files changed

+325
-59
lines changed

9 files changed

+325
-59
lines changed

libcxx/docs/FeatureTestMacroTable.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ Status
380380
--------------------------------------------------- -----------------
381381
``__cpp_lib_string_resize_and_overwrite`` ``202110L``
382382
--------------------------------------------------- -----------------
383-
``__cpp_lib_to_string`` *unimplemented*
383+
``__cpp_lib_to_string`` ``202306L``
384384
--------------------------------------------------- -----------------
385385
``__cpp_lib_to_underlying`` ``202102L``
386386
--------------------------------------------------- -----------------

libcxx/docs/Status/Cxx2cPapers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"Paper #","Group","Paper Name","Meeting","Status","First released version","Labels"
22
"`P2497R0 <https://wg21.link/P2497R0>`__","LWG","Testing for success or failure of ``<charconv>`` functions","Varna June 2023","|Complete|","18.0",""
33
"`P2592R3 <https://wg21.link/P2592R3>`__","LWG","Hashing support for ``std::chrono`` value classes","Varna June 2023","","",""
4-
"`P2587R3 <https://wg21.link/P2587R3>`__","LWG","``to_string`` or not ``to_string``","Varna June 2023","","","|format|"
4+
"`P2587R3 <https://wg21.link/P2587R3>`__","LWG","``to_string`` or not ``to_string``","Varna June 2023","|Complete|","18.0","|format|"
55
"`P2562R1 <https://wg21.link/P2562R1>`__","LWG","``constexpr`` Stable Sorting","Varna June 2023","","",""
66
"`P2545R4 <https://wg21.link/P2545R4>`__","LWG","Read-Copy Update (RCU)","Varna June 2023","","",""
77
"`P2530R3 <https://wg21.link/P2530R3>`__","LWG","Hazard Pointers for C++26","Varna June 2023","","",""

libcxx/include/version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ __cpp_lib_within_lifetime 202306L <type_traits>
473473
# define __cpp_lib_stdatomic_h 202011L
474474
# define __cpp_lib_string_contains 202011L
475475
# define __cpp_lib_string_resize_and_overwrite 202110L
476-
// # define __cpp_lib_to_string 202306L
476+
# define __cpp_lib_to_string 202306L
477477
# define __cpp_lib_to_underlying 202102L
478478
// # define __cpp_lib_tuple_like 202207L
479479
# define __cpp_lib_unreachable 202202L

libcxx/src/string.cpp

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <cerrno>
1111
#include <charconv>
1212
#include <cstdlib>
13+
#include <format>
1314
#include <limits>
1415
#include <stdexcept>
1516
#include <string>
@@ -247,6 +248,36 @@ long double stold(const wstring& str, size_t* idx) { return as_float<long double
247248

248249
// to_string
249250

251+
#if _LIBCPP_STD_VER >= 26
252+
253+
string to_string(int val) { return std::format("{}", val); }
254+
string to_string(long val) { return std::format("{}", val); }
255+
string to_string(long long val) { return std::format("{}", val); }
256+
string to_string(unsigned val) { return std::format("{}", val); }
257+
string to_string(unsigned long val) { return std::format("{}", val); }
258+
string to_string(unsigned long long val) { return std::format("{}", val); }
259+
260+
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
261+
wstring to_wstring(int val) { return std::format(L"{}", val); }
262+
wstring to_wstring(long val) { return std::format(L"{}", val); }
263+
wstring to_wstring(long long val) { return std::format(L"{}", val); }
264+
wstring to_wstring(unsigned val) { return std::format(L"{}", val); }
265+
wstring to_wstring(unsigned long val) { return std::format(L"{}", val); }
266+
wstring to_wstring(unsigned long long val) { return std::format(L"{}", val); }
267+
# endif
268+
269+
string to_string(float val) { return std::format("{}", val); }
270+
string to_string(double val) { return std::format("{}", val); }
271+
string to_string(long double val) { return std::format("{}", val); }
272+
273+
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
274+
wstring to_wstring(float val) { return std::format(L"{}", val); }
275+
wstring to_wstring(double val) { return std::format(L"{}", val); }
276+
wstring to_wstring(long double val) { return std::format(L"{}", val); }
277+
# endif
278+
279+
#else
280+
250281
namespace {
251282

252283
// as_string
@@ -283,7 +314,7 @@ struct initial_string<string> {
283314
}
284315
};
285316

286-
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
317+
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
287318
template <>
288319
struct initial_string<wstring> {
289320
wstring operator()() const {
@@ -296,13 +327,13 @@ struct initial_string<wstring> {
296327
typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t* __restrict, ...);
297328

298329
inline wide_printf get_swprintf() {
299-
# ifndef _LIBCPP_MSVCRT
330+
# ifndef _LIBCPP_MSVCRT
300331
return swprintf;
301-
# else
332+
# else
302333
return static_cast<int(__cdecl*)(wchar_t* __restrict, size_t, const wchar_t* __restrict, ...)>(_snwprintf);
303-
# endif
334+
# endif
304335
}
305-
#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
336+
# endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
306337

307338
template <typename S, typename V>
308339
S i_to_string(V v) {
@@ -325,23 +356,25 @@ string to_string(unsigned val) { return i_to_string< string>(val); }
325356
string to_string(unsigned long val) { return i_to_string< string>(val); }
326357
string to_string(unsigned long long val) { return i_to_string< string>(val); }
327358

328-
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
359+
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
329360
wstring to_wstring(int val) { return i_to_string<wstring>(val); }
330361
wstring to_wstring(long val) { return i_to_string<wstring>(val); }
331362
wstring to_wstring(long long val) { return i_to_string<wstring>(val); }
332363
wstring to_wstring(unsigned val) { return i_to_string<wstring>(val); }
333364
wstring to_wstring(unsigned long val) { return i_to_string<wstring>(val); }
334365
wstring to_wstring(unsigned long long val) { return i_to_string<wstring>(val); }
335-
#endif
366+
# endif
336367

337368
string to_string(float val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }
338369
string to_string(double val) { return as_string(snprintf, initial_string< string>()(), "%f", val); }
339370
string to_string(long double val) { return as_string(snprintf, initial_string< string>()(), "%Lf", val); }
340371

341-
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
372+
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
342373
wstring to_wstring(float val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }
343374
wstring to_wstring(double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%f", val); }
344375
wstring to_wstring(long double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%Lf", val); }
345-
#endif
376+
# endif
377+
378+
#endif // _LIBCPP_STD_VER >= 26
346379

347380
_LIBCPP_END_NAMESPACE_STD

libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -364,17 +364,11 @@
364364
# error "__cpp_lib_string_view should have the value 201803L in c++23"
365365
# endif
366366

367-
# if !defined(_LIBCPP_VERSION)
368-
# ifndef __cpp_lib_to_string
369-
# error "__cpp_lib_to_string should be defined in c++23"
370-
# endif
371-
# if __cpp_lib_to_string != 202306L
372-
# error "__cpp_lib_to_string should have the value 202306L in c++23"
373-
# endif
374-
# else // _LIBCPP_VERSION
375-
# ifdef __cpp_lib_to_string
376-
# error "__cpp_lib_to_string should not be defined because it is unimplemented in libc++!"
377-
# endif
367+
# ifndef __cpp_lib_to_string
368+
# error "__cpp_lib_to_string should be defined in c++23"
369+
# endif
370+
# if __cpp_lib_to_string != 202306L
371+
# error "__cpp_lib_to_string should have the value 202306L in c++23"
378372
# endif
379373

380374
#elif TEST_STD_VER > 23
@@ -462,17 +456,11 @@
462456
# error "__cpp_lib_string_view should have the value 201803L in c++26"
463457
# endif
464458

465-
# if !defined(_LIBCPP_VERSION)
466-
# ifndef __cpp_lib_to_string
467-
# error "__cpp_lib_to_string should be defined in c++26"
468-
# endif
469-
# if __cpp_lib_to_string != 202306L
470-
# error "__cpp_lib_to_string should have the value 202306L in c++26"
471-
# endif
472-
# else // _LIBCPP_VERSION
473-
# ifdef __cpp_lib_to_string
474-
# error "__cpp_lib_to_string should not be defined because it is unimplemented in libc++!"
475-
# endif
459+
# ifndef __cpp_lib_to_string
460+
# error "__cpp_lib_to_string should be defined in c++26"
461+
# endif
462+
# if __cpp_lib_to_string != 202306L
463+
# error "__cpp_lib_to_string should have the value 202306L in c++26"
476464
# endif
477465

478466
#endif // TEST_STD_VER > 23

libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5706,17 +5706,11 @@
57065706
# endif
57075707
# endif
57085708

5709-
# if !defined(_LIBCPP_VERSION)
5710-
# ifndef __cpp_lib_to_string
5711-
# error "__cpp_lib_to_string should be defined in c++23"
5712-
# endif
5713-
# if __cpp_lib_to_string != 202306L
5714-
# error "__cpp_lib_to_string should have the value 202306L in c++23"
5715-
# endif
5716-
# else // _LIBCPP_VERSION
5717-
# ifdef __cpp_lib_to_string
5718-
# error "__cpp_lib_to_string should not be defined because it is unimplemented in libc++!"
5719-
# endif
5709+
# ifndef __cpp_lib_to_string
5710+
# error "__cpp_lib_to_string should be defined in c++23"
5711+
# endif
5712+
# if __cpp_lib_to_string != 202306L
5713+
# error "__cpp_lib_to_string should have the value 202306L in c++23"
57205714
# endif
57215715

57225716
# ifndef __cpp_lib_to_underlying
@@ -7474,17 +7468,11 @@
74747468
# endif
74757469
# endif
74767470

7477-
# if !defined(_LIBCPP_VERSION)
7478-
# ifndef __cpp_lib_to_string
7479-
# error "__cpp_lib_to_string should be defined in c++26"
7480-
# endif
7481-
# if __cpp_lib_to_string != 202306L
7482-
# error "__cpp_lib_to_string should have the value 202306L in c++26"
7483-
# endif
7484-
# else // _LIBCPP_VERSION
7485-
# ifdef __cpp_lib_to_string
7486-
# error "__cpp_lib_to_string should not be defined because it is unimplemented in libc++!"
7487-
# endif
7471+
# ifndef __cpp_lib_to_string
7472+
# error "__cpp_lib_to_string should be defined in c++26"
7473+
# endif
7474+
# if __cpp_lib_to_string != 202306L
7475+
# error "__cpp_lib_to_string should have the value 202306L in c++26"
74887476
# endif
74897477

74907478
# ifndef __cpp_lib_to_underlying

0 commit comments

Comments
 (0)