Skip to content

Commit

Permalink
[libc++] Complete <charconv> for 64-bit long double platforms
Browse files Browse the repository at this point in the history
  • Loading branch information
frederick-vs-ja committed Nov 21, 2024
1 parent 6377ae4 commit f2c0478
Show file tree
Hide file tree
Showing 11 changed files with 88 additions and 33 deletions.
4 changes: 2 additions & 2 deletions libcxx/docs/FeatureTestMacroTable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_string_view`` ``201606L``
---------------------------------------------------------- -----------------
``__cpp_lib_to_chars`` *unimplemented*
``__cpp_lib_to_chars`` ``201611L``
---------------------------------------------------------- -----------------
``__cpp_lib_transparent_operators`` ``201510L``
---------------------------------------------------------- -----------------
Expand Down Expand Up @@ -490,7 +490,7 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_text_encoding`` *unimplemented*
---------------------------------------------------------- -----------------
``__cpp_lib_to_chars`` *unimplemented*
``__cpp_lib_to_chars`` ``202306L``
---------------------------------------------------------- -----------------
``__cpp_lib_to_string`` *unimplemented*
---------------------------------------------------------- -----------------
Expand Down
4 changes: 4 additions & 0 deletions libcxx/docs/ReleaseNotes/20.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ What's New in Libc++ 20.0.0?
Implemented Papers
------------------

- P0067R5: Elementary string conversions is implemented for platforms
where ``long double`` has the same format as ``double`` (`Github <https://github.com/llvm/llvm-project/issues/99940>`__)
- P0619R4: Reviewing Deprecated Facilities of C++17 for C++20 (`Github <https://github.com/llvm/llvm-project/issues/99985>`__)
- P0682R1: Repairing elementary string conversions is implemented for platforms
where ``long double`` has the same format as ``double`` (`Github <https://github.com/llvm/llvm-project/issues/99952>`__)
- P2747R2: ``constexpr`` placement new (`Github <https://github.com/llvm/llvm-project/issues/105427>`__)
- P2609R3: Relaxing Ranges Just A Smidge (`Github <https://github.com/llvm/llvm-project/issues/105253>`__)
- P2985R0: A type trait for detecting virtual base classes (`Github <https://github.com/llvm/llvm-project/issues/105432>`__)
Expand Down
4 changes: 2 additions & 2 deletions libcxx/docs/Status/Cxx17Papers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
"`P0394R4 <https://wg21.link/P0394R4>`__","Hotel Parallelifornia: terminate() for Parallel Algorithms Exception Handling","2016-06 (Oulu)","|Complete|","17",""
"","","","","",""
"`P0003R5 <https://wg21.link/P0003R5>`__","Removing Deprecated Exception Specifications from C++17","2016-11 (Issaquah)","|Complete|","5",""
"`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``."
"`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``."
"`P0403R1 <https://wg21.link/P0403R1>`__","Literal suffixes for ``basic_string_view``\ ","2016-11 (Issaquah)","|Complete|","4",""
"`P0414R2 <https://wg21.link/P0414R2>`__","Merging shared_ptr changes from Library Fundamentals to C++17","2016-11 (Issaquah)","|Complete|","11",""
"`P0418R2 <https://wg21.link/P0418R2>`__","Fail or succeed: there is no atomic lattice","2016-11 (Issaquah)","","",""
Expand Down Expand Up @@ -109,5 +109,5 @@
"`P0618R0 <https://wg21.link/P0618R0>`__","Deprecating <codecvt>","2017-02 (Kona)","|Complete|","15",""
"`P0623R0 <https://wg21.link/P0623R0>`__","Final C++17 Parallel Algorithms Fixes","2017-02 (Kona)","|Nothing To Do|","",""
"","","","","",""
"`P0682R1 <https://wg21.link/P0682R1>`__","Repairing elementary string conversions","2017-07 (Toronto)","","",""
"`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``."
"`P0739R0 <https://wg21.link/P0739R0>`__","Some improvements to class template argument deduction integration into the standard library","2017-07 (Toronto)","|Complete|","5",""
12 changes: 12 additions & 0 deletions libcxx/include/__charconv/from_chars_floating_point.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ from_chars(const char* __first, const char* __last, double& __value, chars_forma
return std::__from_chars<double>(__first, __last, __value, __fmt);
}

# if _LIBCPP_LONG_DOUBLE_IS_DOUBLE
_LIBCPP_AVAILABILITY_FROM_CHARS_FLOATING_POINT _LIBCPP_HIDE_FROM_ABI inline from_chars_result
from_chars(const char* __first, const char* __last, long double& __value, chars_format __fmt = chars_format::general) {
double __dval;
const auto __result = std::__from_chars<double>(__first, __last, __dval, __fmt);
if (__result.ec != errc::invalid_argument)
__value = __dval;
return __result;
}
// TODO: Complete the implementation for platforms where long double has a different format from double.
# endif

#endif // _LIBCPP_STD_VER >= 17

_LIBCPP_END_NAMESPACE_STD
Expand Down
6 changes: 6 additions & 0 deletions libcxx/include/__config
Original file line number Diff line number Diff line change
Expand Up @@ -1231,6 +1231,12 @@ typedef __char32_t char32_t;
# define _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER 0
# endif

# if defined(_MSC_VER) || __SIZEOF_LONG_DOUBLE__ == __SIZEOF_DOUBLE__
# define _LIBCPP_LONG_DOUBLE_IS_DOUBLE 1
# else
# define _LIBCPP_LONG_DOUBLE_IS_DOUBLE 0
# endif

#endif // __cplusplus

#endif // _LIBCPP___CONFIG
8 changes: 6 additions & 2 deletions libcxx/include/version
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,9 @@ __cpp_lib_void_t 201411L <type_traits>
# define __cpp_lib_shared_ptr_arrays 201611L
# define __cpp_lib_shared_ptr_weak_type 201606L
# define __cpp_lib_string_view 201606L
// # define __cpp_lib_to_chars 201611L
# if _LIBCPP_LONG_DOUBLE_IS_DOUBLE
# define __cpp_lib_to_chars 201611L
# endif
# undef __cpp_lib_transparent_operators
# define __cpp_lib_transparent_operators 201510L
# define __cpp_lib_type_trait_variable_templates 201510L
Expand Down Expand Up @@ -572,8 +574,10 @@ __cpp_lib_void_t 201411L <type_traits>
# define __cpp_lib_string_view 202403L
// # define __cpp_lib_submdspan 202306L
// # define __cpp_lib_text_encoding 202306L
# if _LIBCPP_LONG_DOUBLE_IS_DOUBLE
# undef __cpp_lib_to_chars
// # define __cpp_lib_to_chars 202306L
# define __cpp_lib_to_chars 202306L
# endif
// # define __cpp_lib_to_string 202306L
# undef __cpp_lib_tuple_like
// # define __cpp_lib_tuple_like 202311L
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,16 @@
# error "__cpp_lib_constexpr_charconv should not be defined before c++23"
# endif

# if !defined(_LIBCPP_VERSION)
# if defined(TEST_LONG_DOUBLE_IS_DOUBLE)
# ifndef __cpp_lib_to_chars
# error "__cpp_lib_to_chars should be defined in c++17"
# endif
# if __cpp_lib_to_chars != 201611L
# error "__cpp_lib_to_chars should have the value 201611L in c++17"
# endif
# else // _LIBCPP_VERSION
# else
# ifdef __cpp_lib_to_chars
# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!"
# endif
# endif

Expand All @@ -69,16 +69,16 @@
# error "__cpp_lib_constexpr_charconv should not be defined before c++23"
# endif

# if !defined(_LIBCPP_VERSION)
# if defined(TEST_LONG_DOUBLE_IS_DOUBLE)
# ifndef __cpp_lib_to_chars
# error "__cpp_lib_to_chars should be defined in c++20"
# endif
# if __cpp_lib_to_chars != 201611L
# error "__cpp_lib_to_chars should have the value 201611L in c++20"
# endif
# else // _LIBCPP_VERSION
# else
# ifdef __cpp_lib_to_chars
# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!"
# endif
# endif

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

# if !defined(_LIBCPP_VERSION)
# if defined(TEST_LONG_DOUBLE_IS_DOUBLE)
# ifndef __cpp_lib_to_chars
# error "__cpp_lib_to_chars should be defined in c++23"
# endif
# if __cpp_lib_to_chars != 201611L
# error "__cpp_lib_to_chars should have the value 201611L in c++23"
# endif
# else // _LIBCPP_VERSION
# else
# ifdef __cpp_lib_to_chars
# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!"
# endif
# endif

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

# if !defined(_LIBCPP_VERSION)
# if defined(TEST_LONG_DOUBLE_IS_DOUBLE)
# ifndef __cpp_lib_to_chars
# error "__cpp_lib_to_chars should be defined in c++26"
# endif
# if __cpp_lib_to_chars != 202306L
# error "__cpp_lib_to_chars should have the value 202306L in c++26"
# endif
# else // _LIBCPP_VERSION
# else
# ifdef __cpp_lib_to_chars
# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!"
# endif
# endif

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3081,16 +3081,16 @@
# error "__cpp_lib_to_array should not be defined before c++20"
# endif

# if !defined(_LIBCPP_VERSION)
# if defined(TEST_LONG_DOUBLE_IS_DOUBLE)
# ifndef __cpp_lib_to_chars
# error "__cpp_lib_to_chars should be defined in c++17"
# endif
# if __cpp_lib_to_chars != 201611L
# error "__cpp_lib_to_chars should have the value 201611L in c++17"
# endif
# else // _LIBCPP_VERSION
# else
# ifdef __cpp_lib_to_chars
# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!"
# endif
# endif

Expand Down Expand Up @@ -4471,16 +4471,16 @@
# error "__cpp_lib_to_array should have the value 201907L in c++20"
# endif

# if !defined(_LIBCPP_VERSION)
# if defined(TEST_LONG_DOUBLE_IS_DOUBLE)
# ifndef __cpp_lib_to_chars
# error "__cpp_lib_to_chars should be defined in c++20"
# endif
# if __cpp_lib_to_chars != 201611L
# error "__cpp_lib_to_chars should have the value 201611L in c++20"
# endif
# else // _LIBCPP_VERSION
# else
# ifdef __cpp_lib_to_chars
# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!"
# endif
# endif

Expand Down Expand Up @@ -6077,16 +6077,16 @@
# error "__cpp_lib_to_array should have the value 201907L in c++23"
# endif

# if !defined(_LIBCPP_VERSION)
# if defined(TEST_LONG_DOUBLE_IS_DOUBLE)
# ifndef __cpp_lib_to_chars
# error "__cpp_lib_to_chars should be defined in c++23"
# endif
# if __cpp_lib_to_chars != 201611L
# error "__cpp_lib_to_chars should have the value 201611L in c++23"
# endif
# else // _LIBCPP_VERSION
# else
# ifdef __cpp_lib_to_chars
# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!"
# endif
# endif

Expand Down Expand Up @@ -8007,16 +8007,16 @@
# error "__cpp_lib_to_array should have the value 201907L in c++26"
# endif

# if !defined(_LIBCPP_VERSION)
# if defined(TEST_LONG_DOUBLE_IS_DOUBLE)
# ifndef __cpp_lib_to_chars
# error "__cpp_lib_to_chars should be defined in c++26"
# endif
# if __cpp_lib_to_chars != 202306L
# error "__cpp_lib_to_chars should have the value 202306L in c++26"
# endif
# else // _LIBCPP_VERSION
# else
# ifdef __cpp_lib_to_chars
# error "__cpp_lib_to_chars should not be defined because it is unimplemented in libc++!"
# error "__cpp_lib_to_chars should not be defined when the requirement 'defined(TEST_LONG_DOUBLE_IS_DOUBLE)' is not met!"
# endif
# endif

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
//
// from_chars_result from_chars(const char* first, const char* last,
// double& value, chars_format fmt = chars_format::general)
//
// from_chars_result from_chars(const char* first, const char* last,
// long double& value, chars_format fmt = chars_format::general)

#include <array>
#include <charconv>
Expand Down Expand Up @@ -1518,6 +1521,25 @@ struct test_hex {
// test/std/utilities/charconv/charconv.msvc/test.cpp
// uses random values. This tests contains errors found by this test.
void test_random_errors() {
#ifdef TEST_LONG_DOUBLE_IS_DOUBLE
{
const char* s = "4.219902180869891e-2788";
const char* last = s + std::strlen(s) - 1;

// last + 1 contains a digit. When that value is parsed the exponent is
// e-2788 which returns std::errc::result_out_of_range and the value 0.
// the proper exponent is e-278, which can be represented by a
// long double whose format is same as double.

long double value = 0.25L;
std::from_chars_result result = std::from_chars(s, last, value);

assert(result.ec == std::errc{});
assert(result.ptr == last);
assert(value == 4.219902180869891e-278L);
}
// TODO: Add more precise cases when the implementation for long double is complete.
#endif
{
const char* s = "4.219902180869891e-2788";
const char* last = s + std::strlen(s) - 1;
Expand Down
6 changes: 5 additions & 1 deletion libcxx/test/support/charconv_test_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,11 @@ auto all_unsigned = type_list<
>();
auto integrals = concat(all_signed, all_unsigned);

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

template <template <typename> class Fn, typename... Ts>
TEST_CONSTEXPR_CXX23 void
Expand Down
7 changes: 5 additions & 2 deletions libcxx/utils/generate_feature_test_macro_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -1333,7 +1333,8 @@ def add_version_header(tc):
"c++26": 202306, # P2497R0 Testing for success or failure of <charconv> functions
},
"headers": ["charconv"],
"unimplemented": True,
"test_suite_guard": "defined(TEST_LONG_DOUBLE_IS_DOUBLE)",
"libcxx_guard": "_LIBCPP_LONG_DOUBLE_IS_DOUBLE",
},
{
"name": "__cpp_lib_to_string",
Expand Down Expand Up @@ -1532,7 +1533,9 @@ def produce_macros_definition_for_std(std):
result += "# if %s\n" % tc["libcxx_guard"]
inner_indent += 2
if get_value_before(tc["values"], std) is not None:
assert "test_suite_guard" not in tc.keys()
# TRANSITION, __cpp_lib_to_chars has different values
# but needs to be guarded.
# assert "test_suite_guard" not in tc.keys()
result += "# undef %s\n" % tc["name"]
line = "#%sdefine %s" % ((" " * inner_indent), tc["name"])
line += " " * (indent - len(line))
Expand Down

0 comments on commit f2c0478

Please sign in to comment.