Skip to content

Commit

Permalink
[libcxx][libc] Hand in Hand PoC with from_chars
Browse files Browse the repository at this point in the history
DO NOT MERGE, PROOF OF CONCEPT ONLY.

This patch aims to demonstrate the utility of sharing code between libc
and libc++ by using the libc float conversion code in the libc++
function from_chars. This patch adds from_chars for float and double
(long double is possible but was causing errors so was skipped here), as
well as a test to demonstrate that it works.

This is very much just a proof of concept, not intended to be committed
as-is. The from_chars code written is copied from the libc parsing code
and is not functionally complete, nor does it follow the correct coding
style.
  • Loading branch information
nikic authored and mordante committed Oct 20, 2024
1 parent 2c93598 commit 88ea875
Show file tree
Hide file tree
Showing 36 changed files with 2,365 additions and 21 deletions.
22 changes: 22 additions & 0 deletions libc/shared/fp_bits.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//===-- Floating point number utils -----------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SHARED_FP_BITS_H
#define LLVM_LIBC_SHARED_FP_BITS_H

#include "src/__support/FPUtil/FPBits.h"

namespace LIBC_NAMESPACE_DECL {
namespace shared {

using fputil::FPBits;

} // namespace shared
} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SHARED_FP_BITS_H
27 changes: 27 additions & 0 deletions libc/shared/str_to_float.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//===-- String to float conversion utils ------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SHARED_STR_TO_FLOAT_H
#define LLVM_LIBC_SHARED_STR_TO_FLOAT_H

#include "src/__support/str_to_float.h"

namespace LIBC_NAMESPACE_DECL {
namespace shared {

using internal::ExpandedFloat;
using internal::FloatConvertReturn;
using internal::RoundDirection;

using internal::binary_exp_to_float;
using internal::decimal_exp_to_float;

} // namespace shared
} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SHARED_STR_TO_FLOAT_H
24 changes: 24 additions & 0 deletions libc/shared/str_to_integer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//===-- String to int conversion utils --------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SHARED_STR_TO_INTEGER_H
#define LLVM_LIBC_SHARED_STR_TO_INTEGER_H

#include "src/__support/str_to_integer.h"

namespace LIBC_NAMESPACE_DECL {
namespace shared {

using LIBC_NAMESPACE::StrToNumResult;

using internal::strtointeger;

} // namespace shared
} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SHARED_STR_TO_INTEGER_H
12 changes: 12 additions & 0 deletions libc/src/__support/FPUtil/FPBits.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
//
//===----------------------------------------------------------------------===//

// -----------------------------------------------------------------------------
// **** WARNING ****
// This file is shared with libc++. You should also be careful when adding
// dependencies to this file, since it needs to build for all libc++ targets.
// -----------------------------------------------------------------------------

#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_FPBITS_H
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_FPBITS_H

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

// -----------------------------------------------------------------------------
// **** WARNING ****
// This interface is shared with libc++, if you change this interface you need
// to update it in both libc and libc++. You should also be careful when adding
// dependencies to this file, since it needs to build for all libc++ targets.
// -----------------------------------------------------------------------------
// A generic class to manipulate C++ floating point formats.
// It derives its functionality to FPRepImpl above.
template <typename T>
Expand Down
11 changes: 11 additions & 0 deletions libc/src/__support/high_precision_decimal.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
//
//===----------------------------------------------------------------------===//

// -----------------------------------------------------------------------------
// **** WARNING ****
// This file is shared with libc++. You should also be careful when adding
// dependencies to this file, since it needs to build for all libc++ targets.
// -----------------------------------------------------------------------------

#ifndef LLVM_LIBC_SRC___SUPPORT_HIGH_PRECISION_DECIMAL_H
#define LLVM_LIBC_SRC___SUPPORT_HIGH_PRECISION_DECIMAL_H

Expand All @@ -23,6 +29,11 @@ struct LShiftTableEntry {
char const *power_of_five;
};

// -----------------------------------------------------------------------------
// **** WARNING ****
// This interface is shared with libc++, if you change this interface you need
// to update it in both libc and libc++.
// -----------------------------------------------------------------------------
// This is used in both this file and in the main str_to_float.h.
// TODO: Figure out where to put this.
enum class RoundDirection { Up, Down, Nearest };
Expand Down
26 changes: 26 additions & 0 deletions libc/src/__support/str_to_float.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
//
//===----------------------------------------------------------------------===//

// -----------------------------------------------------------------------------
// **** WARNING ****
// This file is shared with libc++. You should also be careful when adding
// dependencies to this file, since it needs to build for all libc++ targets.
// -----------------------------------------------------------------------------

#ifndef LLVM_LIBC_SRC___SUPPORT_STR_TO_FLOAT_H
#define LLVM_LIBC_SRC___SUPPORT_STR_TO_FLOAT_H

Expand All @@ -32,11 +38,21 @@
namespace LIBC_NAMESPACE_DECL {
namespace internal {

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

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

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

// -----------------------------------------------------------------------------
// **** WARNING ****
// This interface is shared with libc++, if you change this interface you need
// to update it in both libc and libc++.
// -----------------------------------------------------------------------------
// Takes a mantissa and base 2 exponent and converts it into its closest
// floating point type T equivalient. Since the exponent is already in the right
// form, this is mostly just shifting and rounding. This is used for hexadecimal
Expand Down
11 changes: 11 additions & 0 deletions libc/src/__support/str_to_integer.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
//
//===----------------------------------------------------------------------===//

// -----------------------------------------------------------------------------
// **** WARNING ****
// This file is shared with libc++. You should also be careful when adding
// dependencies to this file, since it needs to build for all libc++ targets.
// -----------------------------------------------------------------------------

#ifndef LLVM_LIBC_SRC___SUPPORT_STR_TO_INTEGER_H
#define LLVM_LIBC_SRC___SUPPORT_STR_TO_INTEGER_H

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

// -----------------------------------------------------------------------------
// **** WARNING ****
// This interface is shared with libc++, if you change this interface you need
// to update it in both libc and libc++.
// -----------------------------------------------------------------------------
// Takes a pointer to a string and the base to convert to. This function is used
// as the backend for all of the string to int functions.
template <class T>
Expand Down
11 changes: 11 additions & 0 deletions libc/src/__support/str_to_num_result.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
//
//===----------------------------------------------------------------------===//

// -----------------------------------------------------------------------------
// **** WARNING ****
// This file is shared with libc++. You should also be careful when adding
// dependencies to this file, since it needs to build for all libc++ targets.
// -----------------------------------------------------------------------------

#ifndef LLVM_LIBC_SRC___SUPPORT_STR_TO_NUM_RESULT_H
#define LLVM_LIBC_SRC___SUPPORT_STR_TO_NUM_RESULT_H

Expand All @@ -16,6 +22,11 @@

namespace LIBC_NAMESPACE_DECL {

// -----------------------------------------------------------------------------
// **** WARNING ****
// This interface is shared with libc++, if you change this interface you need
// to update it in both libc and libc++.
// -----------------------------------------------------------------------------
template <typename T> struct StrToNumResult {
T value;
int error;
Expand Down
2 changes: 1 addition & 1 deletion 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.0",""
"","","","","",""
"`P0003R5 <https://wg21.link/P0003R5>`__","Removing Deprecated Exception Specifications from C++17","2016-11 (Issaquah)","|Complete|","5.0",""
"`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``."
"`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."
"`P0403R1 <https://wg21.link/P0403R1>`__","Literal suffixes for ``basic_string_view``\ ","2016-11 (Issaquah)","|Complete|","4.0",""
"`P0414R2 <https://wg21.link/P0414R2>`__","Merging shared_ptr changes from Library Fundamentals to C++17","2016-11 (Issaquah)","|Complete|","11.0",""
"`P0418R2 <https://wg21.link/P0418R2>`__","Fail or succeed: there is no atomic lattice","2016-11 (Issaquah)","","",""
Expand Down
1 change: 1 addition & 0 deletions libcxx/docs/Status/Cxx2cIssues.csv
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,5 @@
"","","","","",""
"`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",""
"`LWG4139 <https://wg21.link/LWG4139>`__","§[time.zone.leap] recursive constraint in <=>","Not Adopted Yet","|Complete|","20.0",""
"`LWG3456 <https://wg21.link/LWG3456>`__","Pattern used by std::from_chars is underspecified (option B)",,"Not Yet Adopted","|Complete|","20.0",""
"","","","","",""
1 change: 1 addition & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ set(files
__bit/rotate.h
__bit_reference
__charconv/chars_format.h
__charconv/from_chars_floating_point.h
__charconv/from_chars_integral.h
__charconv/from_chars_result.h
__charconv/tables.h
Expand Down
73 changes: 73 additions & 0 deletions libcxx/include/__charconv/from_chars_floating_point.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___CHARCONV_FROM_CHARS_FLOATING_POINT_H
#define _LIBCPP___CHARCONV_FROM_CHARS_FLOATING_POINT_H

#include <__assert>
#include <__charconv/chars_format.h>
#include <__charconv/from_chars_result.h>
#include <__config>
#include <__system_error/errc.h>
#include <cstddef>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_PUSH_MACROS
#include <__undef_macros>

_LIBCPP_BEGIN_NAMESPACE_STD

#if _LIBCPP_STD_VER >= 17

template <class _Fp>
struct __from_chars_result {
_Fp __value;
ptrdiff_t __n;
errc __ec;
};

template <class _Fp>
_LIBCPP_EXPORTED_FROM_ABI __from_chars_result<_Fp> __from_chars_floating_point(
[[clang::noescape]] const char* __first, [[clang::noescape]] const char* __last, chars_format __fmt);

extern template __from_chars_result<float> __from_chars_floating_point(
[[clang::noescape]] const char* __first, [[clang::noescape]] const char* __last, chars_format __fmt);

extern template __from_chars_result<double> __from_chars_floating_point(
[[clang::noescape]] const char* __first, [[clang::noescape]] const char* __last, chars_format __fmt);

template <class _Fp>
_LIBCPP_HIDE_FROM_ABI from_chars_result
__from_chars(const char* __first, const char* __last, _Fp& __value, chars_format __fmt) {
__from_chars_result<_Fp> __r = std::__from_chars_floating_point<_Fp>(__first, __last, __fmt);
if (__r.__ec != errc::invalid_argument)
__value = __r.__value;
return {__first + __r.__n, __r.__ec};
}

_LIBCPP_AVAILABILITY_FROM_CHARS_FLOATING_POINT _LIBCPP_HIDE_FROM_ABI inline from_chars_result
from_chars(const char* __first, const char* __last, float& __value, chars_format __fmt = chars_format::general) {
return std::__from_chars<float>(__first, __last, __value, __fmt);
}

_LIBCPP_AVAILABILITY_FROM_CHARS_FLOATING_POINT _LIBCPP_HIDE_FROM_ABI inline from_chars_result
from_chars(const char* __first, const char* __last, double& __value, chars_format __fmt = chars_format::general) {
return std::__from_chars<double>(__first, __last, __value, __fmt);
}

#endif // _LIBCPP_STD_VER >= 17

_LIBCPP_END_NAMESPACE_STD

_LIBCPP_POP_MACROS

#endif // _LIBCPP___CHARCONV_FROM_CHARS_FLOATING_POINT_H
13 changes: 13 additions & 0 deletions libcxx/include/__configuration/availability.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@
// in all versions of the library are available.
#if defined(_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS)

# define _LIBCPP_INTRODUCED_IN_LLVM_20 1
# define _LIBCPP_INTRODUCED_IN_LLVM_20_ATTRIBUTE /* nothing */

# define _LIBCPP_INTRODUCED_IN_LLVM_19 1
# define _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE /* nothing */

Expand Down Expand Up @@ -132,6 +135,11 @@

// clang-format off

// LLVM 20
// TODO: Fill this in
# define _LIBCPP_INTRODUCED_IN_LLVM_20 0
# define _LIBCPP_INTRODUCED_IN_LLVM_20_ATTRIBUTE __attribute__((unavailable))

// LLVM 19
// TODO: Fill this in
# define _LIBCPP_INTRODUCED_IN_LLVM_19 0
Expand Down Expand Up @@ -409,6 +417,11 @@
#define _LIBCPP_AVAILABILITY_HAS_BAD_EXPECTED_ACCESS_KEY_FUNCTION _LIBCPP_INTRODUCED_IN_LLVM_19
#define _LIBCPP_AVAILABILITY_BAD_EXPECTED_ACCESS_KEY_FUNCTION _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE

// This controls the availability of floating-point std::from_chars functions.
// These overloads were added later than the integer overloads.
#define _LIBCPP_AVAILABILITY_HAS_FROM_CHARS_FLOATING_POINT _LIBCPP_INTRODUCED_IN_LLVM_20
#define _LIBCPP_AVAILABILITY_FROM_CHARS_FLOATING_POINT _LIBCPP_INTRODUCED_IN_LLVM_20_ATTRIBUTE

// Define availability attributes that depend on _LIBCPP_HAS_EXCEPTIONS.
// Those are defined in terms of the availability attributes above, and
// should not be vendor-specific.
Expand Down
7 changes: 7 additions & 0 deletions libcxx/include/charconv
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ namespace std {
constexpr from_chars_result from_chars(const char* first, const char* last,
see below& value, int base = 10); // constexpr since C++23
from_chars_result from_chars(const char* first, const char* last,
float& value, chars_format fmt);
from_chars_result from_chars(const char* first, const char* last,
double& value, chars_format fmt);
} // namespace std
*/
Expand All @@ -73,6 +79,7 @@ namespace std {

#if _LIBCPP_STD_VER >= 17
# include <__charconv/chars_format.h>
# include <__charconv/from_chars_floating_point.h>
# include <__charconv/from_chars_integral.h>
# include <__charconv/from_chars_result.h>
# include <__charconv/tables.h>
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,7 @@ module std [system] {

module charconv {
module chars_format { header "__charconv/chars_format.h" }
module from_chars_floating_point { header "__charconv/from_chars_floating_point.h" }
module from_chars_integral { header "__charconv/from_chars_integral.h" }
module from_chars_result { header "__charconv/from_chars_result.h" }
module tables { header "__charconv/tables.h" }
Expand Down
Loading

0 comments on commit 88ea875

Please sign in to comment.