Skip to content

Commit f5c3933

Browse files
[libc++] Complete <charconv> for 64-bit long double platforms
1 parent 97b2903 commit f5c3933

File tree

11 files changed

+88
-33
lines changed

11 files changed

+88
-33
lines changed

libcxx/docs/FeatureTestMacroTable.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ Status
152152
---------------------------------------------------------- -----------------
153153
``__cpp_lib_string_view`` ``201606L``
154154
---------------------------------------------------------- -----------------
155-
``__cpp_lib_to_chars`` *unimplemented*
155+
``__cpp_lib_to_chars`` ``201611L``
156156
---------------------------------------------------------- -----------------
157157
``__cpp_lib_transparent_operators`` ``201510L``
158158
---------------------------------------------------------- -----------------
@@ -490,7 +490,7 @@ Status
490490
---------------------------------------------------------- -----------------
491491
``__cpp_lib_text_encoding`` *unimplemented*
492492
---------------------------------------------------------- -----------------
493-
``__cpp_lib_to_chars`` *unimplemented*
493+
``__cpp_lib_to_chars`` ``202306L``
494494
---------------------------------------------------------- -----------------
495495
``__cpp_lib_to_string`` *unimplemented*
496496
---------------------------------------------------------- -----------------

libcxx/docs/ReleaseNotes/20.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ What's New in Libc++ 20.0.0?
3838
Implemented Papers
3939
------------------
4040

41+
- P0067R5: Elementary string conversions is implemented for platforms
42+
where ``long double`` has the same format as ``double`` (`Github <https://github.com/llvm/llvm-project/issues/99940>`__)
4143
- P0619R4: Reviewing Deprecated Facilities of C++17 for C++20 (`Github <https://github.com/llvm/llvm-project/issues/99985>`__)
44+
- P0682R1: Repairing elementary string conversions is implemented for platforms
45+
where ``long double`` has the same format as ``double`` (`Github <https://github.com/llvm/llvm-project/issues/99952>`__)
4246
- P2747R2: ``constexpr`` placement new (`Github <https://github.com/llvm/llvm-project/issues/105427>`__)
4347
- P2609R3: Relaxing Ranges Just A Smidge (`Github <https://github.com/llvm/llvm-project/issues/105253>`__)
4448
- P2985R0: A type trait for detecting virtual base classes (`Github <https://github.com/llvm/llvm-project/issues/105432>`__)

libcxx/docs/Status/Cxx17Papers.csv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
"`P0394R4 <https://wg21.link/P0394R4>`__","Hotel Parallelifornia: terminate() for Parallel Algorithms Exception Handling","2016-06 (Oulu)","|Complete|","17",""
7272
"","","","","",""
7373
"`P0003R5 <https://wg21.link/P0003R5>`__","Removing Deprecated Exception Specifications from C++17","2016-11 (Issaquah)","|Complete|","5",""
74-
"`P0067R5 <https://wg21.link/P0067R5>`__","Elementary string conversions, revision 5","2016-11 (Issaquah)","|Partial|","","For integer types, ``std::(to|from)_chars`` has been available since v7; for ``float`` and ``double``, ``std::to_chars`` since v14 and ``std::from_chars`` since v20. Support is complete except for ``long double``."
74+
"`P0067R5 <https://wg21.link/P0067R5>`__","Elementary string conversions, revision 5","2016-11 (Issaquah)","|Partial|","","For integer types, ``std::(to|from)_chars`` has been available since v7; for ``float`` and ``double``, ``std::to_chars`` since v14 and ``std::from_chars`` since v20. Support is complete except for ``long double`` on platforms where its format is different ``double``."
7575
"`P0403R1 <https://wg21.link/P0403R1>`__","Literal suffixes for ``basic_string_view``\ ","2016-11 (Issaquah)","|Complete|","4",""
7676
"`P0414R2 <https://wg21.link/P0414R2>`__","Merging shared_ptr changes from Library Fundamentals to C++17","2016-11 (Issaquah)","|Complete|","11",""
7777
"`P0418R2 <https://wg21.link/P0418R2>`__","Fail or succeed: there is no atomic lattice","2016-11 (Issaquah)","","",""
@@ -109,5 +109,5 @@
109109
"`P0618R0 <https://wg21.link/P0618R0>`__","Deprecating <codecvt>","2017-02 (Kona)","|Complete|","15",""
110110
"`P0623R0 <https://wg21.link/P0623R0>`__","Final C++17 Parallel Algorithms Fixes","2017-02 (Kona)","|Nothing To Do|","",""
111111
"","","","","",""
112-
"`P0682R1 <https://wg21.link/P0682R1>`__","Repairing elementary string conversions","2017-07 (Toronto)","","",""
112+
"`P0682R1 <https://wg21.link/P0682R1>`__","Repairing elementary string conversions","2017-07 (Toronto)","|Partial|","","Support is complete in v20 on platforms where ``long double`` has the same format as ``double``."
113113
"`P0739R0 <https://wg21.link/P0739R0>`__","Some improvements to class template argument deduction integration into the standard library","2017-07 (Toronto)","|Complete|","5",""

libcxx/include/__charconv/from_chars_floating_point.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,18 @@ from_chars(const char* __first, const char* __last, double& __value, chars_forma
6464
return std::__from_chars<double>(__first, __last, __value, __fmt);
6565
}
6666

67+
# if _LIBCPP_LONG_DOUBLE_IS_DOUBLE
68+
_LIBCPP_AVAILABILITY_FROM_CHARS_FLOATING_POINT _LIBCPP_HIDE_FROM_ABI inline from_chars_result
69+
from_chars(const char* __first, const char* __last, long double& __value, chars_format __fmt = chars_format::general) {
70+
double __dval;
71+
const auto __result = std::__from_chars<double>(__first, __last, __dval, __fmt);
72+
if (__result.ec == errc{})
73+
__value = __dval;
74+
return __result;
75+
}
76+
// TODO: Complete the implementation for platforms where long double has a different format from double.
77+
# endif
78+
6779
#endif // _LIBCPP_STD_VER >= 17
6880

6981
_LIBCPP_END_NAMESPACE_STD

libcxx/include/__config

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,6 +1231,12 @@ typedef __char32_t char32_t;
12311231
# define _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER 0
12321232
# endif
12331233

1234+
# if defined(_MSC_VER) || __SIZEOF_LONG_DOUBLE__ == __SIZEOF_DOUBLE__
1235+
# define _LIBCPP_LONG_DOUBLE_IS_DOUBLE 1
1236+
# else
1237+
# define _LIBCPP_LONG_DOUBLE_IS_DOUBLE 0
1238+
# endif
1239+
12341240
#endif // __cplusplus
12351241

12361242
#endif // _LIBCPP___CONFIG

libcxx/include/version

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,9 @@ __cpp_lib_void_t 201411L <type_traits>
357357
# define __cpp_lib_shared_ptr_arrays 201611L
358358
# define __cpp_lib_shared_ptr_weak_type 201606L
359359
# define __cpp_lib_string_view 201606L
360-
// # define __cpp_lib_to_chars 201611L
360+
# if _LIBCPP_LONG_DOUBLE_IS_DOUBLE
361+
# define __cpp_lib_to_chars 201611L
362+
# endif
361363
# undef __cpp_lib_transparent_operators
362364
# define __cpp_lib_transparent_operators 201510L
363365
# define __cpp_lib_type_trait_variable_templates 201510L
@@ -572,8 +574,10 @@ __cpp_lib_void_t 201411L <type_traits>
572574
# define __cpp_lib_string_view 202403L
573575
// # define __cpp_lib_submdspan 202306L
574576
// # define __cpp_lib_text_encoding 202306L
577+
# if _LIBCPP_LONG_DOUBLE_IS_DOUBLE
575578
# undef __cpp_lib_to_chars
576-
// # define __cpp_lib_to_chars 202306L
579+
# define __cpp_lib_to_chars 202306L
580+
# endif
577581
// # define __cpp_lib_to_string 202306L
578582
# undef __cpp_lib_tuple_like
579583
// # define __cpp_lib_tuple_like 202311L

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,16 @@
5050
# error "__cpp_lib_constexpr_charconv should not be defined before c++23"
5151
# endif
5252

53-
# if !defined(_LIBCPP_VERSION)
53+
# if defined(TEST_LONG_DOUBLE_IS_DOUBLE)
5454
# ifndef __cpp_lib_to_chars
5555
# error "__cpp_lib_to_chars should be defined in c++17"
5656
# endif
5757
# if __cpp_lib_to_chars != 201611L
5858
# error "__cpp_lib_to_chars should have the value 201611L in c++17"
5959
# endif
60-
# else // _LIBCPP_VERSION
60+
# else
6161
# ifdef __cpp_lib_to_chars
62-
# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
62+
# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!"
6363
# endif
6464
# endif
6565

@@ -69,16 +69,16 @@
6969
# error "__cpp_lib_constexpr_charconv should not be defined before c++23"
7070
# endif
7171

72-
# if !defined(_LIBCPP_VERSION)
72+
# if defined(TEST_LONG_DOUBLE_IS_DOUBLE)
7373
# ifndef __cpp_lib_to_chars
7474
# error "__cpp_lib_to_chars should be defined in c++20"
7575
# endif
7676
# if __cpp_lib_to_chars != 201611L
7777
# error "__cpp_lib_to_chars should have the value 201611L in c++20"
7878
# endif
79-
# else // _LIBCPP_VERSION
79+
# else
8080
# ifdef __cpp_lib_to_chars
81-
# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
81+
# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!"
8282
# endif
8383
# endif
8484

@@ -91,16 +91,16 @@
9191
# error "__cpp_lib_constexpr_charconv should have the value 202207L in c++23"
9292
# endif
9393

94-
# if !defined(_LIBCPP_VERSION)
94+
# if defined(TEST_LONG_DOUBLE_IS_DOUBLE)
9595
# ifndef __cpp_lib_to_chars
9696
# error "__cpp_lib_to_chars should be defined in c++23"
9797
# endif
9898
# if __cpp_lib_to_chars != 201611L
9999
# error "__cpp_lib_to_chars should have the value 201611L in c++23"
100100
# endif
101-
# else // _LIBCPP_VERSION
101+
# else
102102
# ifdef __cpp_lib_to_chars
103-
# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
103+
# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!"
104104
# endif
105105
# endif
106106

@@ -113,16 +113,16 @@
113113
# error "__cpp_lib_constexpr_charconv should have the value 202207L in c++26"
114114
# endif
115115

116-
# if !defined(_LIBCPP_VERSION)
116+
# if defined(TEST_LONG_DOUBLE_IS_DOUBLE)
117117
# ifndef __cpp_lib_to_chars
118118
# error "__cpp_lib_to_chars should be defined in c++26"
119119
# endif
120120
# if __cpp_lib_to_chars != 202306L
121121
# error "__cpp_lib_to_chars should have the value 202306L in c++26"
122122
# endif
123-
# else // _LIBCPP_VERSION
123+
# else
124124
# ifdef __cpp_lib_to_chars
125-
# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
125+
# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!"
126126
# endif
127127
# endif
128128

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3081,16 +3081,16 @@
30813081
# error "__cpp_lib_to_array should not be defined before c++20"
30823082
# endif
30833083

3084-
# if !defined(_LIBCPP_VERSION)
3084+
# if defined(TEST_LONG_DOUBLE_IS_DOUBLE)
30853085
# ifndef __cpp_lib_to_chars
30863086
# error "__cpp_lib_to_chars should be defined in c++17"
30873087
# endif
30883088
# if __cpp_lib_to_chars != 201611L
30893089
# error "__cpp_lib_to_chars should have the value 201611L in c++17"
30903090
# endif
3091-
# else // _LIBCPP_VERSION
3091+
# else
30923092
# ifdef __cpp_lib_to_chars
3093-
# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
3093+
# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!"
30943094
# endif
30953095
# endif
30963096

@@ -4471,16 +4471,16 @@
44714471
# error "__cpp_lib_to_array should have the value 201907L in c++20"
44724472
# endif
44734473

4474-
# if !defined(_LIBCPP_VERSION)
4474+
# if defined(TEST_LONG_DOUBLE_IS_DOUBLE)
44754475
# ifndef __cpp_lib_to_chars
44764476
# error "__cpp_lib_to_chars should be defined in c++20"
44774477
# endif
44784478
# if __cpp_lib_to_chars != 201611L
44794479
# error "__cpp_lib_to_chars should have the value 201611L in c++20"
44804480
# endif
4481-
# else // _LIBCPP_VERSION
4481+
# else
44824482
# ifdef __cpp_lib_to_chars
4483-
# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
4483+
# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!"
44844484
# endif
44854485
# endif
44864486

@@ -6077,16 +6077,16 @@
60776077
# error "__cpp_lib_to_array should have the value 201907L in c++23"
60786078
# endif
60796079

6080-
# if !defined(_LIBCPP_VERSION)
6080+
# if defined(TEST_LONG_DOUBLE_IS_DOUBLE)
60816081
# ifndef __cpp_lib_to_chars
60826082
# error "__cpp_lib_to_chars should be defined in c++23"
60836083
# endif
60846084
# if __cpp_lib_to_chars != 201611L
60856085
# error "__cpp_lib_to_chars should have the value 201611L in c++23"
60866086
# endif
6087-
# else // _LIBCPP_VERSION
6087+
# else
60886088
# ifdef __cpp_lib_to_chars
6089-
# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
6089+
# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!"
60906090
# endif
60916091
# endif
60926092

@@ -8007,16 +8007,16 @@
80078007
# error "__cpp_lib_to_array should have the value 201907L in c++26"
80088008
# endif
80098009

8010-
# if !defined(_LIBCPP_VERSION)
8010+
# if defined(TEST_LONG_DOUBLE_IS_DOUBLE)
80118011
# ifndef __cpp_lib_to_chars
80128012
# error "__cpp_lib_to_chars should be defined in c++26"
80138013
# endif
80148014
# if __cpp_lib_to_chars != 202306L
80158015
# error "__cpp_lib_to_chars should have the value 202306L in c++26"
80168016
# endif
8017-
# else // _LIBCPP_VERSION
8017+
# else
80188018
# ifdef __cpp_lib_to_chars
8019-
# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
8019+
# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!"
80208020
# endif
80218021
# endif
80228022

libcxx/test/std/utilities/charconv/charconv.from.chars/floating_point.pass.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
//
1616
// from_chars_result from_chars(const char* first, const char* last,
1717
// double& value, chars_format fmt = chars_format::general)
18+
//
19+
// from_chars_result from_chars(const char* first, const char* last,
20+
// long double& value, chars_format fmt = chars_format::general)
1821

1922
#include <array>
2023
#include <charconv>
@@ -1518,6 +1521,25 @@ struct test_hex {
15181521
// test/std/utilities/charconv/charconv.msvc/test.cpp
15191522
// uses random values. This tests contains errors found by this test.
15201523
void test_random_errors() {
1524+
#ifdef TEST_LONG_DOUBLE_IS_DOUBLE
1525+
{
1526+
const char* s = "4.219902180869891e-2788";
1527+
const char* last = s + std::strlen(s) - 1;
1528+
1529+
// last + 1 contains a digit. When that value is parsed the exponent is
1530+
// e-2788 which returns std::errc::result_out_of_range and the value 0.
1531+
// the proper exponent is e-278, which can be represented by a
1532+
// long double whose format is same as double.
1533+
1534+
long double value = 0.25L;
1535+
std::from_chars_result result = std::from_chars(s, last, value);
1536+
1537+
assert(result.ec == std::errc{});
1538+
assert(result.ptr == last);
1539+
assert(value == 4.219902180869891e-278L);
1540+
}
1541+
// TODO: Add more precise cases when the implementation for long double is complete.
1542+
#endif
15211543
{
15221544
const char* s = "4.219902180869891e-2788";
15231545
const char* last = s + std::strlen(s) - 1;

libcxx/test/support/charconv_test_helpers.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,11 @@ auto all_unsigned = type_list<
317317
>();
318318
auto integrals = concat(all_signed, all_unsigned);
319319

320-
auto all_floats = type_list< float, double >(); //TODO: Add long double
320+
#ifdef TEST_LONG_DOUBLE_IS_DOUBLE // TODO: Remove this condition when the implementation for long double is complete.
321+
auto all_floats = type_list< float, double, long double >();
322+
#else
323+
auto all_floats = type_list< float, double >();
324+
#endif
321325

322326
template <template <typename> class Fn, typename... Ts>
323327
TEST_CONSTEXPR_CXX23 void

libcxx/utils/generate_feature_test_macro_components.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,7 +1333,8 @@ def add_version_header(tc):
13331333
"c++26": 202306, # P2497R0 Testing for success or failure of <charconv> functions
13341334
},
13351335
"headers": ["charconv"],
1336-
"unimplemented": True,
1336+
"test_suite_guard": "defined(TEST_LONG_DOUBLE_IS_DOUBLE)",
1337+
"libcxx_guard": "_LIBCPP_LONG_DOUBLE_IS_DOUBLE",
13371338
},
13381339
{
13391340
"name": "__cpp_lib_to_string",
@@ -1532,7 +1533,9 @@ def produce_macros_definition_for_std(std):
15321533
result += "# if %s\n" % tc["libcxx_guard"]
15331534
inner_indent += 2
15341535
if get_value_before(tc["values"], std) is not None:
1535-
assert "test_suite_guard" not in tc.keys()
1536+
# TRANSITION, __cpp_lib_to_chars has different values
1537+
# but needs to be guarded.
1538+
# assert "test_suite_guard" not in tc.keys()
15361539
result += "# undef %s\n" % tc["name"]
15371540
line = "#%sdefine %s" % ((" " * inner_indent), tc["name"])
15381541
line += " " * (indent - len(line))

0 commit comments

Comments
 (0)