Skip to content

Commit 967de3d

Browse files
[libcxx][libc] Hand in Hand PoC with from_chars
Implements std::from_chars for float and double. The implementation uses LLVM-libc to do the real parsing. Since this is the first time libc++ uses LLVM-libc there is a bit of additional infrastructure code. The patch is based on the [RFC] Project Hand In Hand (LLVM-libc/libc++ code sharing) https://discourse.llvm.org/t/rfc-project-hand-in-hand-llvm-libc-libc-code-sharing/77701
1 parent 2c93598 commit 967de3d

36 files changed

+2365
-21
lines changed

libc/shared/fp_bits.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//===-- Floating point number utils -----------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SHARED_FP_BITS_H
10+
#define LLVM_LIBC_SHARED_FP_BITS_H
11+
12+
#include "src/__support/FPUtil/FPBits.h"
13+
14+
namespace LIBC_NAMESPACE_DECL {
15+
namespace shared {
16+
17+
using fputil::FPBits;
18+
19+
} // namespace shared
20+
} // namespace LIBC_NAMESPACE_DECL
21+
22+
#endif // LLVM_LIBC_SHARED_FP_BITS_H

libc/shared/str_to_float.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===-- String to float conversion utils ------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SHARED_STR_TO_FLOAT_H
10+
#define LLVM_LIBC_SHARED_STR_TO_FLOAT_H
11+
12+
#include "src/__support/str_to_float.h"
13+
14+
namespace LIBC_NAMESPACE_DECL {
15+
namespace shared {
16+
17+
using internal::ExpandedFloat;
18+
using internal::FloatConvertReturn;
19+
using internal::RoundDirection;
20+
21+
using internal::binary_exp_to_float;
22+
using internal::decimal_exp_to_float;
23+
24+
} // namespace shared
25+
} // namespace LIBC_NAMESPACE_DECL
26+
27+
#endif // LLVM_LIBC_SHARED_STR_TO_FLOAT_H

libc/shared/str_to_integer.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//===-- String to int conversion utils --------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SHARED_STR_TO_INTEGER_H
10+
#define LLVM_LIBC_SHARED_STR_TO_INTEGER_H
11+
12+
#include "src/__support/str_to_integer.h"
13+
14+
namespace LIBC_NAMESPACE_DECL {
15+
namespace shared {
16+
17+
using LIBC_NAMESPACE::StrToNumResult;
18+
19+
using internal::strtointeger;
20+
21+
} // namespace shared
22+
} // namespace LIBC_NAMESPACE_DECL
23+
24+
#endif // LLVM_LIBC_SHARED_STR_TO_INTEGER_H

libc/src/__support/FPUtil/FPBits.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
// -----------------------------------------------------------------------------
10+
// **** WARNING ****
11+
// This file is shared with libc++. You should also be careful when adding
12+
// dependencies to this file, since it needs to build for all libc++ targets.
13+
// -----------------------------------------------------------------------------
14+
915
#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_FPBITS_H
1016
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_FPBITS_H
1117

@@ -795,6 +801,12 @@ template <typename T> LIBC_INLINE static constexpr FPType get_fp_type() {
795801
static_assert(cpp::always_false<UnqualT>, "Unsupported type");
796802
}
797803

804+
// -----------------------------------------------------------------------------
805+
// **** WARNING ****
806+
// This interface is shared with libc++, if you change this interface you need
807+
// to update it in both libc and libc++. You should also be careful when adding
808+
// dependencies to this file, since it needs to build for all libc++ targets.
809+
// -----------------------------------------------------------------------------
798810
// A generic class to manipulate C++ floating point formats.
799811
// It derives its functionality to FPRepImpl above.
800812
template <typename T>

libc/src/__support/high_precision_decimal.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
// -----------------------------------------------------------------------------
10+
// **** WARNING ****
11+
// This file is shared with libc++. You should also be careful when adding
12+
// dependencies to this file, since it needs to build for all libc++ targets.
13+
// -----------------------------------------------------------------------------
14+
915
#ifndef LLVM_LIBC_SRC___SUPPORT_HIGH_PRECISION_DECIMAL_H
1016
#define LLVM_LIBC_SRC___SUPPORT_HIGH_PRECISION_DECIMAL_H
1117

@@ -23,6 +29,11 @@ struct LShiftTableEntry {
2329
char const *power_of_five;
2430
};
2531

32+
// -----------------------------------------------------------------------------
33+
// **** WARNING ****
34+
// This interface is shared with libc++, if you change this interface you need
35+
// to update it in both libc and libc++.
36+
// -----------------------------------------------------------------------------
2637
// This is used in both this file and in the main str_to_float.h.
2738
// TODO: Figure out where to put this.
2839
enum class RoundDirection { Up, Down, Nearest };

libc/src/__support/str_to_float.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
// -----------------------------------------------------------------------------
10+
// **** WARNING ****
11+
// This file is shared with libc++. You should also be careful when adding
12+
// dependencies to this file, since it needs to build for all libc++ targets.
13+
// -----------------------------------------------------------------------------
14+
915
#ifndef LLVM_LIBC_SRC___SUPPORT_STR_TO_FLOAT_H
1016
#define LLVM_LIBC_SRC___SUPPORT_STR_TO_FLOAT_H
1117

@@ -32,11 +38,21 @@
3238
namespace LIBC_NAMESPACE_DECL {
3339
namespace internal {
3440

41+
// -----------------------------------------------------------------------------
42+
// **** WARNING ****
43+
// This interface is shared with libc++, if you change this interface you need
44+
// to update it in both libc and libc++.
45+
// -----------------------------------------------------------------------------
3546
template <class T> struct ExpandedFloat {
3647
typename fputil::FPBits<T>::StorageType mantissa;
3748
int32_t exponent;
3849
};
3950

51+
// -----------------------------------------------------------------------------
52+
// **** WARNING ****
53+
// This interface is shared with libc++, if you change this interface you need
54+
// to update it in both libc and libc++.
55+
// -----------------------------------------------------------------------------
4056
template <class T> struct FloatConvertReturn {
4157
ExpandedFloat<T> num = {0, 0};
4258
int error = 0;
@@ -637,6 +653,11 @@ template <> LIBC_INLINE constexpr int32_t get_lower_bound<double>() {
637653
return -(309 + 15 + 20);
638654
}
639655

656+
// -----------------------------------------------------------------------------
657+
// **** WARNING ****
658+
// This interface is shared with libc++, if you change this interface you need
659+
// to update it in both libc and libc++.
660+
// -----------------------------------------------------------------------------
640661
// Takes a mantissa and base 10 exponent and converts it into its closest
641662
// floating point type T equivalient. First we try the Eisel-Lemire algorithm,
642663
// then if that fails then we fall back to a more accurate algorithm for
@@ -716,6 +737,11 @@ LIBC_INLINE FloatConvertReturn<T> decimal_exp_to_float(
716737
return output;
717738
}
718739

740+
// -----------------------------------------------------------------------------
741+
// **** WARNING ****
742+
// This interface is shared with libc++, if you change this interface you need
743+
// to update it in both libc and libc++.
744+
// -----------------------------------------------------------------------------
719745
// Takes a mantissa and base 2 exponent and converts it into its closest
720746
// floating point type T equivalient. Since the exponent is already in the right
721747
// form, this is mostly just shifting and rounding. This is used for hexadecimal

libc/src/__support/str_to_integer.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
// -----------------------------------------------------------------------------
10+
// **** WARNING ****
11+
// This file is shared with libc++. You should also be careful when adding
12+
// dependencies to this file, since it needs to build for all libc++ targets.
13+
// -----------------------------------------------------------------------------
14+
915
#ifndef LLVM_LIBC_SRC___SUPPORT_STR_TO_INTEGER_H
1016
#define LLVM_LIBC_SRC___SUPPORT_STR_TO_INTEGER_H
1117

@@ -73,6 +79,11 @@ LIBC_INLINE int infer_base(const char *__restrict src, size_t src_len) {
7379
return 10;
7480
}
7581

82+
// -----------------------------------------------------------------------------
83+
// **** WARNING ****
84+
// This interface is shared with libc++, if you change this interface you need
85+
// to update it in both libc and libc++.
86+
// -----------------------------------------------------------------------------
7687
// Takes a pointer to a string and the base to convert to. This function is used
7788
// as the backend for all of the string to int functions.
7889
template <class T>

libc/src/__support/str_to_num_result.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
// -----------------------------------------------------------------------------
10+
// **** WARNING ****
11+
// This file is shared with libc++. You should also be careful when adding
12+
// dependencies to this file, since it needs to build for all libc++ targets.
13+
// -----------------------------------------------------------------------------
14+
915
#ifndef LLVM_LIBC_SRC___SUPPORT_STR_TO_NUM_RESULT_H
1016
#define LLVM_LIBC_SRC___SUPPORT_STR_TO_NUM_RESULT_H
1117

@@ -16,6 +22,11 @@
1622

1723
namespace LIBC_NAMESPACE_DECL {
1824

25+
// -----------------------------------------------------------------------------
26+
// **** WARNING ****
27+
// This interface is shared with libc++, if you change this interface you need
28+
// to update it in both libc and libc++.
29+
// -----------------------------------------------------------------------------
1930
template <typename T> struct StrToNumResult {
2031
T value;
2132
int error;

libcxx/docs/Status/Cxx17Papers.csv

Lines changed: 1 addition & 1 deletion
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.0",""
7272
"","","","","",""
7373
"`P0003R5 <https://wg21.link/P0003R5>`__","Removing Deprecated Exception Specifications from C++17","2016-11 (Issaquah)","|Complete|","5.0",""
74-
"`P0067R5 <https://wg21.link/P0067R5>`__","Elementary string conversions, revision 5","2016-11 (Issaquah)","|Partial|","","``std::(to|from)_chars`` for integrals has been available since version 7.0. ``std::to_chars`` for ``float`` and ``double`` since version 14.0 ``std::to_chars`` for ``long double`` uses the implementation for ``double``."
74+
"`P0067R5 <https://wg21.link/P0067R5>`__","Elementary string conversions, revision 5","2016-11 (Issaquah)","|Partial|","","``std::(to|from)_chars`` for integrals has been available since version 7.0. ``std::to_chars`` for ``float`` and ``double`` since version 14.0 ``std::to_chars`` for ``long double`` uses the implementation for ``double``. ``std::from_chars`` for ``float`` and ``double`` since version 20.0."
7575
"`P0403R1 <https://wg21.link/P0403R1>`__","Literal suffixes for ``basic_string_view``\ ","2016-11 (Issaquah)","|Complete|","4.0",""
7676
"`P0414R2 <https://wg21.link/P0414R2>`__","Merging shared_ptr changes from Library Fundamentals to C++17","2016-11 (Issaquah)","|Complete|","11.0",""
7777
"`P0418R2 <https://wg21.link/P0418R2>`__","Fail or succeed: there is no atomic lattice","2016-11 (Issaquah)","","",""

libcxx/docs/Status/Cxx2cIssues.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,5 @@
7878
"","","","","",""
7979
"`LWG3343 <https://wg21.link/LWG3343>`__","Ordering of calls to ``unlock()`` and ``notify_all()`` in Effects element of ``notify_all_at_thread_exit()`` should be reversed","Not Adopted Yet","|Complete|","16.0",""
8080
"`LWG4139 <https://wg21.link/LWG4139>`__","§[time.zone.leap] recursive constraint in <=>","Not Adopted Yet","|Complete|","20.0",""
81+
"`LWG3456 <https://wg21.link/LWG3456>`__","Pattern used by std::from_chars is underspecified (option B)",,"Not Yet Adopted","|Complete|","20.0",""
8182
"","","","","",""

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ set(files
235235
__bit/rotate.h
236236
__bit_reference
237237
__charconv/chars_format.h
238+
__charconv/from_chars_floating_point.h
238239
__charconv/from_chars_integral.h
239240
__charconv/from_chars_result.h
240241
__charconv/tables.h
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef _LIBCPP___CHARCONV_FROM_CHARS_FLOATING_POINT_H
11+
#define _LIBCPP___CHARCONV_FROM_CHARS_FLOATING_POINT_H
12+
13+
#include <__assert>
14+
#include <__charconv/chars_format.h>
15+
#include <__charconv/from_chars_result.h>
16+
#include <__config>
17+
#include <__system_error/errc.h>
18+
#include <cstddef>
19+
20+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
21+
# pragma GCC system_header
22+
#endif
23+
24+
_LIBCPP_PUSH_MACROS
25+
#include <__undef_macros>
26+
27+
_LIBCPP_BEGIN_NAMESPACE_STD
28+
29+
#if _LIBCPP_STD_VER >= 17
30+
31+
template <class _Fp>
32+
struct __from_chars_result {
33+
_Fp __value;
34+
ptrdiff_t __n;
35+
errc __ec;
36+
};
37+
38+
template <class _Fp>
39+
_LIBCPP_EXPORTED_FROM_ABI __from_chars_result<_Fp> __from_chars_floating_point(
40+
[[clang::noescape]] const char* __first, [[clang::noescape]] const char* __last, chars_format __fmt);
41+
42+
extern template __from_chars_result<float> __from_chars_floating_point(
43+
[[clang::noescape]] const char* __first, [[clang::noescape]] const char* __last, chars_format __fmt);
44+
45+
extern template __from_chars_result<double> __from_chars_floating_point(
46+
[[clang::noescape]] const char* __first, [[clang::noescape]] const char* __last, chars_format __fmt);
47+
48+
template <class _Fp>
49+
_LIBCPP_HIDE_FROM_ABI from_chars_result
50+
__from_chars(const char* __first, const char* __last, _Fp& __value, chars_format __fmt) {
51+
__from_chars_result<_Fp> __r = std::__from_chars_floating_point<_Fp>(__first, __last, __fmt);
52+
if (__r.__ec != errc::invalid_argument)
53+
__value = __r.__value;
54+
return {__first + __r.__n, __r.__ec};
55+
}
56+
57+
_LIBCPP_AVAILABILITY_FROM_CHARS_FLOATING_POINT _LIBCPP_HIDE_FROM_ABI inline from_chars_result
58+
from_chars(const char* __first, const char* __last, float& __value, chars_format __fmt = chars_format::general) {
59+
return std::__from_chars<float>(__first, __last, __value, __fmt);
60+
}
61+
62+
_LIBCPP_AVAILABILITY_FROM_CHARS_FLOATING_POINT _LIBCPP_HIDE_FROM_ABI inline from_chars_result
63+
from_chars(const char* __first, const char* __last, double& __value, chars_format __fmt = chars_format::general) {
64+
return std::__from_chars<double>(__first, __last, __value, __fmt);
65+
}
66+
67+
#endif // _LIBCPP_STD_VER >= 17
68+
69+
_LIBCPP_END_NAMESPACE_STD
70+
71+
_LIBCPP_POP_MACROS
72+
73+
#endif // _LIBCPP___CHARCONV_FROM_CHARS_FLOATING_POINT_H

libcxx/include/__configuration/availability.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@
8787
// in all versions of the library are available.
8888
#if defined(_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS)
8989

90+
# define _LIBCPP_INTRODUCED_IN_LLVM_20 1
91+
# define _LIBCPP_INTRODUCED_IN_LLVM_20_ATTRIBUTE /* nothing */
92+
9093
# define _LIBCPP_INTRODUCED_IN_LLVM_19 1
9194
# define _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE /* nothing */
9295

@@ -132,6 +135,11 @@
132135

133136
// clang-format off
134137

138+
// LLVM 20
139+
// TODO: Fill this in
140+
# define _LIBCPP_INTRODUCED_IN_LLVM_20 0
141+
# define _LIBCPP_INTRODUCED_IN_LLVM_20_ATTRIBUTE __attribute__((unavailable))
142+
135143
// LLVM 19
136144
// TODO: Fill this in
137145
# define _LIBCPP_INTRODUCED_IN_LLVM_19 0
@@ -409,6 +417,11 @@
409417
#define _LIBCPP_AVAILABILITY_HAS_BAD_EXPECTED_ACCESS_KEY_FUNCTION _LIBCPP_INTRODUCED_IN_LLVM_19
410418
#define _LIBCPP_AVAILABILITY_BAD_EXPECTED_ACCESS_KEY_FUNCTION _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE
411419

420+
// This controls the availability of floating-point std::from_chars functions.
421+
// These overloads were added later than the integer overloads.
422+
#define _LIBCPP_AVAILABILITY_HAS_FROM_CHARS_FLOATING_POINT _LIBCPP_INTRODUCED_IN_LLVM_20
423+
#define _LIBCPP_AVAILABILITY_FROM_CHARS_FLOATING_POINT _LIBCPP_INTRODUCED_IN_LLVM_20_ATTRIBUTE
424+
412425
// Define availability attributes that depend on _LIBCPP_HAS_EXCEPTIONS.
413426
// Those are defined in terms of the availability attributes above, and
414427
// should not be vendor-specific.

libcxx/include/charconv

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ namespace std {
6565
constexpr from_chars_result from_chars(const char* first, const char* last,
6666
see below& value, int base = 10); // constexpr since C++23
6767
68+
from_chars_result from_chars(const char* first, const char* last,
69+
float& value, chars_format fmt);
70+
71+
from_chars_result from_chars(const char* first, const char* last,
72+
double& value, chars_format fmt);
73+
6874
} // namespace std
6975
7076
*/
@@ -73,6 +79,7 @@ namespace std {
7379

7480
#if _LIBCPP_STD_VER >= 17
7581
# include <__charconv/chars_format.h>
82+
# include <__charconv/from_chars_floating_point.h>
7683
# include <__charconv/from_chars_integral.h>
7784
# include <__charconv/from_chars_result.h>
7885
# include <__charconv/tables.h>

libcxx/include/module.modulemap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,7 @@ module std [system] {
898898

899899
module charconv {
900900
module chars_format { header "__charconv/chars_format.h" }
901+
module from_chars_floating_point { header "__charconv/from_chars_floating_point.h" }
901902
module from_chars_integral { header "__charconv/from_chars_integral.h" }
902903
module from_chars_result { header "__charconv/from_chars_result.h" }
903904
module tables { header "__charconv/tables.h" }

0 commit comments

Comments
 (0)