[libcxx][libc] Hand in Hand PoC with from_chars (#91651)
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
This commit is contained in:
22
libc/shared/fp_bits.h
Normal file
22
libc/shared/fp_bits.h
Normal file
@@ -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
libc/shared/str_to_float.h
Normal file
27
libc/shared/str_to_float.h
Normal file
@@ -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
libc/shared/str_to_integer.h
Normal file
24
libc/shared/str_to_integer.h
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)","","",""
|
||||
|
||||
|
@@ -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",""
|
||||
"","","","","",""
|
||||
|
||||
|
@@ -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
|
||||
|
||||
73
libcxx/include/__charconv/from_chars_floating_point.h
Normal file
73
libcxx/include/__charconv/from_chars_floating_point.h
Normal file
@@ -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
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
*/
|
||||
@@ -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>
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -16,6 +16,13 @@ New entries should be added directly below the "Version" header.
|
||||
Version 20.0
|
||||
------------
|
||||
|
||||
* [libcxx][libc] Implements from_chars floating-point
|
||||
|
||||
All platforms
|
||||
-------------
|
||||
Symbol added: _ZNSt3__127__from_chars_floating_pointIdEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE
|
||||
Symbol added: _ZNSt3__127__from_chars_floating_pointIfEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE
|
||||
|
||||
* [libc++] Stop trying to avoid exporting some typeinfo names
|
||||
|
||||
This patch removes the explicit list of symbols to avoid exporting
|
||||
|
||||
@@ -1584,6 +1584,8 @@
|
||||
{'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__127__from_chars_floating_pointIdEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__127__from_chars_floating_pointIfEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'}
|
||||
|
||||
@@ -1220,6 +1220,8 @@
|
||||
{'is_defined': True, 'name': '_ZNSt6__ndk123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIiNS_22__cxx_atomic_base_implIiEEEE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt6__ndk123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt6__ndk125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt6__ndk127__from_chars_floating_pointIdEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt6__ndk127__from_chars_floating_pointIfEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt6__ndk131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt6__ndk132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt6__ndk134__construct_barrier_algorithm_baseERi', 'type': 'FUNC'}
|
||||
|
||||
@@ -1715,6 +1715,8 @@
|
||||
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__119basic_istringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__119basic_ostringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__122__libcpp_verbose_abortEPKcz', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIdEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIfEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__14__fs10filesystem16_FilesystemClock9is_steadyE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
|
||||
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__14__fs10filesystem4path19preferred_separatorE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
|
||||
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
|
||||
@@ -1715,6 +1715,8 @@
|
||||
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__119basic_istringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__119basic_ostringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEaSEOS5_', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__122__libcpp_verbose_abortEPKcz', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIdEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIfEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__14__fs10filesystem16_FilesystemClock9is_steadyE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
|
||||
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__14__fs10filesystem4path19preferred_separatorE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
|
||||
{'import_export': 'wEXP', 'is_defined': True, 'name': '_ZNSt3__16__sortIRNS_6__lessIaaEEPaEEvT0_S5_T_', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
|
||||
|
||||
@@ -1584,6 +1584,8 @@
|
||||
{'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__127__from_chars_floating_pointEPKcS1_RdNS_12chars_formatE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__127__from_chars_floating_pointEPKcS1_RfNS_12chars_formatE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '__ZNSt3__134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'}
|
||||
|
||||
@@ -1220,6 +1220,8 @@
|
||||
{'is_defined': True, 'name': '_ZNSt6__ndk123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIiNS_22__cxx_atomic_base_implIiEEEE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt6__ndk123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt6__ndk125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt6__ndk127__from_chars_floating_pointIdEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt6__ndk127__from_chars_floating_pointIfEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt6__ndk131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt6__ndk132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt6__ndk134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'}
|
||||
|
||||
@@ -1235,6 +1235,8 @@
|
||||
{'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIlNS_22__cxx_atomic_base_implIlEEEE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIdEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIfEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'}
|
||||
|
||||
@@ -1233,6 +1233,8 @@
|
||||
{'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIiNS_22__cxx_atomic_base_implIiEEEE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIdEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIfEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'}
|
||||
|
||||
@@ -1204,6 +1204,8 @@
|
||||
{'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIiNS_22__cxx_atomic_base_implIiEEEE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIdEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__127__from_chars_floating_pointIfEENS_19__from_chars_resultIT_EEPKcS5_NS_12chars_formatE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'}
|
||||
{'is_defined': True, 'name': '_ZNSt3__134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'}
|
||||
|
||||
@@ -31,6 +31,7 @@ set(LIBCXX_SOURCES
|
||||
include/ryu/f2s.h
|
||||
include/ryu/ryu.h
|
||||
include/to_chars_floating_point.h
|
||||
include/from_chars_floating_point.h
|
||||
legacy_pointer_safety.cpp
|
||||
memory.cpp
|
||||
memory_resource.cpp
|
||||
@@ -172,11 +173,14 @@ endif()
|
||||
split_list(LIBCXX_COMPILE_FLAGS)
|
||||
split_list(LIBCXX_LINK_FLAGS)
|
||||
|
||||
include(FindLibcCommonUtils)
|
||||
|
||||
# Build the shared library.
|
||||
add_library(cxx_shared SHARED ${LIBCXX_SOURCES} ${LIBCXX_HEADERS})
|
||||
target_include_directories(cxx_shared PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(cxx_shared PUBLIC cxx-headers libcxx-libc-shared
|
||||
PRIVATE ${LIBCXX_LIBRARIES})
|
||||
PRIVATE ${LIBCXX_LIBRARIES}
|
||||
PRIVATE llvm-libc-common-utilities)
|
||||
set_target_properties(cxx_shared
|
||||
PROPERTIES
|
||||
EXCLUDE_FROM_ALL "$<IF:$<BOOL:${LIBCXX_ENABLE_SHARED}>,FALSE,TRUE>"
|
||||
@@ -267,7 +271,8 @@ add_library(cxx_static STATIC ${LIBCXX_SOURCES} ${LIBCXX_HEADERS})
|
||||
target_include_directories(cxx_static PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(cxx_static PUBLIC cxx-headers libcxx-libc-static
|
||||
PRIVATE ${LIBCXX_LIBRARIES}
|
||||
PRIVATE libcxx-abi-static)
|
||||
PRIVATE libcxx-abi-static
|
||||
PRIVATE llvm-libc-common-utilities)
|
||||
set_target_properties(cxx_static
|
||||
PROPERTIES
|
||||
EXCLUDE_FROM_ALL "$<IF:$<BOOL:${LIBCXX_ENABLE_STATIC}>,FALSE,TRUE>"
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <charconv>
|
||||
#include <string.h>
|
||||
|
||||
#include "include/from_chars_floating_point.h"
|
||||
#include "include/to_chars_floating_point.h"
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
@@ -74,4 +75,15 @@ to_chars_result to_chars(char* __first, char* __last, long double __value, chars
|
||||
__first, __last, static_cast<double>(__value), __fmt, __precision);
|
||||
}
|
||||
|
||||
template <class _Fp>
|
||||
__from_chars_result<_Fp> __from_chars_floating_point(
|
||||
[[clang::noescape]] const char* __first, [[clang::noescape]] const char* __last, chars_format __fmt) {
|
||||
return std::__from_chars_floating_point_impl<_Fp>(__first, __last, __fmt);
|
||||
}
|
||||
|
||||
template __from_chars_result<float> __from_chars_floating_point(
|
||||
[[clang::noescape]] const char* __first, [[clang::noescape]] const char* __last, chars_format __fmt);
|
||||
|
||||
template __from_chars_result<double> __from_chars_floating_point(
|
||||
[[clang::noescape]] const char* __first, [[clang::noescape]] const char* __last, chars_format __fmt);
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
457
libcxx/src/include/from_chars_floating_point.h
Normal file
457
libcxx/src/include/from_chars_floating_point.h
Normal file
@@ -0,0 +1,457 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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_SRC_INCLUDE_FROM_CHARS_FLOATING_POINT_H
|
||||
#define _LIBCPP_SRC_INCLUDE_FROM_CHARS_FLOATING_POINT_H
|
||||
|
||||
// These headers are in the shared LLVM-libc header library.
|
||||
#include "shared/fp_bits.h"
|
||||
#include "shared/str_to_float.h"
|
||||
#include "shared/str_to_integer.h"
|
||||
|
||||
#include <__assert>
|
||||
#include <__config>
|
||||
#include <cctype>
|
||||
#include <charconv>
|
||||
#include <concepts>
|
||||
#include <limits>
|
||||
|
||||
// Included for the _Floating_type_traits class
|
||||
#include "to_chars_floating_point.h"
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
// Parses an infinity string.
|
||||
// Valid strings are case insensitive and contain INF or INFINITY.
|
||||
//
|
||||
// - __first is the first argument to std::from_chars. When the string is invalid
|
||||
// this value is returned as ptr in the result.
|
||||
// - __last is the last argument of std::from_chars.
|
||||
// - __value is the value argument of std::from_chars,
|
||||
// - __ptr is the current position is the input string. This is points beyond
|
||||
// the initial I character.
|
||||
// - __negative whether a valid string represents -inf or +inf.
|
||||
template <floating_point _Fp>
|
||||
__from_chars_result<_Fp>
|
||||
__from_chars_floating_point_inf(const char* const __first, const char* __last, const char* __ptr, bool __negative) {
|
||||
if (__last - __ptr < 2) [[unlikely]]
|
||||
return {_Fp{0}, 0, errc::invalid_argument};
|
||||
|
||||
if (std::tolower(__ptr[0]) != 'n' || std::tolower(__ptr[1]) != 'f') [[unlikely]]
|
||||
return {_Fp{0}, 0, errc::invalid_argument};
|
||||
|
||||
__ptr += 2;
|
||||
|
||||
// At this point the result is valid and contains INF.
|
||||
// When the remaining part contains INITY this will be consumed. Otherwise
|
||||
// only INF is consumed. For example INFINITZ will consume INF and ignore
|
||||
// INITZ.
|
||||
|
||||
if (__last - __ptr >= 5 //
|
||||
&& std::tolower(__ptr[0]) == 'i' //
|
||||
&& std::tolower(__ptr[1]) == 'n' //
|
||||
&& std::tolower(__ptr[2]) == 'i' //
|
||||
&& std::tolower(__ptr[3]) == 't' //
|
||||
&& std::tolower(__ptr[4]) == 'y')
|
||||
__ptr += 5;
|
||||
|
||||
if constexpr (numeric_limits<_Fp>::has_infinity) {
|
||||
if (__negative)
|
||||
return {-std::numeric_limits<_Fp>::infinity(), __ptr - __first, std::errc{}};
|
||||
|
||||
return {std::numeric_limits<_Fp>::infinity(), __ptr - __first, std::errc{}};
|
||||
} else {
|
||||
return {_Fp{0}, __ptr - __first, errc::result_out_of_range};
|
||||
}
|
||||
}
|
||||
|
||||
// Parses a nan string.
|
||||
// Valid strings are case insensitive and contain INF or INFINITY.
|
||||
//
|
||||
// - __first is the first argument to std::from_chars. When the string is invalid
|
||||
// this value is returned as ptr in the result.
|
||||
// - __last is the last argument of std::from_chars.
|
||||
// - __value is the value argument of std::from_chars,
|
||||
// - __ptr is the current position is the input string. This is points beyond
|
||||
// the initial N character.
|
||||
// - __negative whether a valid string represents -nan or +nan.
|
||||
template <floating_point _Fp>
|
||||
__from_chars_result<_Fp>
|
||||
__from_chars_floating_point_nan(const char* const __first, const char* __last, const char* __ptr, bool __negative) {
|
||||
if (__last - __ptr < 2) [[unlikely]]
|
||||
return {_Fp{0}, 0, errc::invalid_argument};
|
||||
|
||||
if (std::tolower(__ptr[0]) != 'a' || std::tolower(__ptr[1]) != 'n') [[unlikely]]
|
||||
return {_Fp{0}, 0, errc::invalid_argument};
|
||||
|
||||
__ptr += 2;
|
||||
|
||||
// At this point the result is valid and contains NAN. When the remaining
|
||||
// part contains ( n-char-sequence_opt ) this will be consumed. Otherwise
|
||||
// only NAN is consumed. For example NAN(abcd will consume NAN and ignore
|
||||
// (abcd.
|
||||
if (__last - __ptr >= 2 && __ptr[0] == '(') {
|
||||
size_t __offset = 1;
|
||||
do {
|
||||
if (__ptr[__offset] == ')') {
|
||||
__ptr += __offset + 1;
|
||||
break;
|
||||
}
|
||||
if (__ptr[__offset] != '_' && !std::isalnum(__ptr[__offset]))
|
||||
break;
|
||||
++__offset;
|
||||
} while (__ptr + __offset != __last);
|
||||
}
|
||||
|
||||
if (__negative)
|
||||
return {-std::numeric_limits<_Fp>::quiet_NaN(), __ptr - __first, std::errc{}};
|
||||
|
||||
return {std::numeric_limits<_Fp>::quiet_NaN(), __ptr - __first, std::errc{}};
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
struct __fractional_constant_result {
|
||||
size_t __offset{size_t(-1)};
|
||||
_Tp __mantissa{0};
|
||||
int __exponent{0};
|
||||
bool __truncated{false};
|
||||
bool __is_valid{false};
|
||||
};
|
||||
|
||||
// Parses the hex constant part of the hexadecimal floating-point value.
|
||||
// - input start of buffer given to from_chars
|
||||
// - __n the number of elements in the buffer
|
||||
// - __offset where to start parsing. The input can have an optional sign, the
|
||||
// offset starts after this sign.
|
||||
template <class _Tp>
|
||||
__fractional_constant_result<_Tp> __parse_fractional_hex_constant(const char* __input, size_t __n, size_t __offset) {
|
||||
__fractional_constant_result<_Tp> __result;
|
||||
|
||||
const _Tp __mantissa_truncate_threshold = numeric_limits<_Tp>::max() / 16;
|
||||
bool __fraction = false;
|
||||
for (; __offset < __n; ++__offset) {
|
||||
if (std::isxdigit(__input[__offset])) {
|
||||
__result.__is_valid = true;
|
||||
|
||||
uint32_t __digit = __input[__offset] - '0';
|
||||
switch (std::tolower(__input[__offset])) {
|
||||
case 'a':
|
||||
__digit = 10;
|
||||
break;
|
||||
case 'b':
|
||||
__digit = 11;
|
||||
break;
|
||||
case 'c':
|
||||
__digit = 12;
|
||||
break;
|
||||
case 'd':
|
||||
__digit = 13;
|
||||
break;
|
||||
case 'e':
|
||||
__digit = 14;
|
||||
break;
|
||||
case 'f':
|
||||
__digit = 15;
|
||||
break;
|
||||
}
|
||||
|
||||
if (__result.__mantissa < __mantissa_truncate_threshold) {
|
||||
__result.__mantissa = (__result.__mantissa * 16) + __digit;
|
||||
if (__fraction)
|
||||
__result.__exponent -= 4;
|
||||
} else {
|
||||
if (__digit > 0)
|
||||
__result.__truncated = true;
|
||||
if (!__fraction)
|
||||
__result.__exponent += 4;
|
||||
}
|
||||
} else if (__input[__offset] == '.') {
|
||||
if (__fraction)
|
||||
break; // this means that __input[__offset] points to a second decimal point, ending the number.
|
||||
|
||||
__fraction = true;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
__result.__offset = __offset;
|
||||
return __result;
|
||||
}
|
||||
|
||||
struct __exponent_result {
|
||||
size_t __offset{size_t(-1)};
|
||||
int __value{0};
|
||||
bool __present{false};
|
||||
};
|
||||
|
||||
// When the exponent is not present the result of the struct contains
|
||||
// __offset, 0, false. This allows using the results unconditionally, the
|
||||
// __present is important for the scientific notation, where the value is
|
||||
// mandatory.
|
||||
__exponent_result __parse_exponent(const char* __input, size_t __n, size_t __offset, char __marker) {
|
||||
if (__offset + 1 < __n && // an exponent always needs at least one digit.
|
||||
std::tolower(__input[__offset]) == __marker && //
|
||||
!std::isspace(__input[__offset + 1]) // leading whitespace is not allowed.
|
||||
) {
|
||||
++__offset;
|
||||
LIBC_NAMESPACE::shared::StrToNumResult<int32_t> __e =
|
||||
LIBC_NAMESPACE::shared::strtointeger<int32_t>(__input + __offset, 10, __n - __offset);
|
||||
// __result.error contains the errno value, 0 or ERANGE these are not interesting.
|
||||
// If the number of characters parsed is 0 it means there was no number.
|
||||
if (__e.parsed_len != 0)
|
||||
return {__offset + __e.parsed_len, __e.value, true};
|
||||
else
|
||||
--__offset; // the assumption of a valid exponent was not true, undo eating the exponent character.
|
||||
}
|
||||
|
||||
return {__offset, 0, false};
|
||||
}
|
||||
|
||||
// Here we do this operation as int64 to avoid overflow.
|
||||
int32_t __merge_exponents(int64_t __fractional, int64_t __exponent, int __max_biased_exponent) {
|
||||
int64_t __sum = __fractional + __exponent;
|
||||
|
||||
if (__sum > __max_biased_exponent)
|
||||
return __max_biased_exponent;
|
||||
|
||||
if (__sum < -__max_biased_exponent)
|
||||
return -__max_biased_exponent;
|
||||
|
||||
return __sum;
|
||||
}
|
||||
|
||||
template <class _Fp, class _Tp>
|
||||
__from_chars_result<_Fp>
|
||||
__calculate_result(_Tp __mantissa, int __exponent, bool __negative, __from_chars_result<_Fp> __result) {
|
||||
auto __r = LIBC_NAMESPACE::shared::FPBits<_Fp>();
|
||||
__r.set_mantissa(__mantissa);
|
||||
__r.set_biased_exponent(__exponent);
|
||||
|
||||
// C17 7.12.1/6
|
||||
// The result underflows if the magnitude of the mathematical result is so
|
||||
// small that the mathematical result cannot be represented, without
|
||||
// extraordinary roundoff error, in an object of the specified type.237) If
|
||||
// the result underflows, the function returns an implementation-defined
|
||||
// value whose magnitude is no greater than the smallest normalized positive
|
||||
// number in the specified type; if the integer expression math_errhandling
|
||||
// & MATH_ERRNO is nonzero, whether errno acquires the value ERANGE is
|
||||
// implementation-defined; if the integer expression math_errhandling &
|
||||
// MATH_ERREXCEPT is nonzero, whether the "underflow" floating-point
|
||||
// exception is raised is implementation-defined.
|
||||
//
|
||||
// LLVM-LIBC sets ERAGNE for subnormal values
|
||||
//
|
||||
// [charconv.from.chars]/1
|
||||
// ... If the parsed value is not in the range representable by the type of
|
||||
// value, value is unmodified and the member ec of the return value is
|
||||
// equal to errc::result_out_of_range. ...
|
||||
//
|
||||
// Undo the ERANGE for subnormal values.
|
||||
if (__result.__ec == errc::result_out_of_range && __r.is_subnormal() && !__r.is_zero())
|
||||
__result.__ec = errc{};
|
||||
|
||||
if (__negative)
|
||||
__result.__value = -__r.get_val();
|
||||
else
|
||||
__result.__value = __r.get_val();
|
||||
|
||||
return __result;
|
||||
}
|
||||
|
||||
// Implements from_chars for decimal floating-point values.
|
||||
// __first forwarded from from_chars
|
||||
// __last forwarded from from_chars
|
||||
// __value forwarded from from_chars
|
||||
// __fmt forwarded from from_chars
|
||||
// __ptr the start of the buffer to parse. This is after the optional sign character.
|
||||
// __negative should __value be set to a negative value?
|
||||
//
|
||||
// This function and __from_chars_floating_point_decimal are similar. However
|
||||
// the similar parts are all in helper functions. So the amount of code
|
||||
// duplication is minimal.
|
||||
template <floating_point _Fp>
|
||||
__from_chars_result<_Fp>
|
||||
__from_chars_floating_point_hex(const char* const __first, const char* __last, const char* __ptr, bool __negative) {
|
||||
size_t __n = __last - __first;
|
||||
ptrdiff_t __offset = __ptr - __first;
|
||||
|
||||
auto __fractional =
|
||||
std::__parse_fractional_hex_constant<typename _Floating_type_traits<_Fp>::_Uint_type>(__first, __n, __offset);
|
||||
if (!__fractional.__is_valid)
|
||||
return {_Fp{0}, 0, errc::invalid_argument};
|
||||
|
||||
auto __parsed_exponent = std::__parse_exponent(__first, __n, __fractional.__offset, 'p');
|
||||
__offset = __parsed_exponent.__offset;
|
||||
int __exponent = std::__merge_exponents(
|
||||
__fractional.__exponent, __parsed_exponent.__value, LIBC_NAMESPACE::shared::FPBits<_Fp>::MAX_BIASED_EXPONENT);
|
||||
|
||||
__from_chars_result<_Fp> __result{_Fp{0}, __offset, {}};
|
||||
LIBC_NAMESPACE::shared::ExpandedFloat<_Fp> __expanded_float = {0, 0};
|
||||
if (__fractional.__mantissa != 0) {
|
||||
auto __temp = LIBC_NAMESPACE::shared::binary_exp_to_float<_Fp>(
|
||||
{__fractional.__mantissa, __exponent},
|
||||
__fractional.__truncated,
|
||||
LIBC_NAMESPACE::shared::RoundDirection::Nearest);
|
||||
__expanded_float = __temp.num;
|
||||
if (__temp.error == ERANGE) {
|
||||
__result.__ec = errc::result_out_of_range;
|
||||
}
|
||||
}
|
||||
|
||||
return std::__calculate_result<_Fp>(__expanded_float.mantissa, __expanded_float.exponent, __negative, __result);
|
||||
}
|
||||
|
||||
// Parses the hex constant part of the decimal float value.
|
||||
// - input start of buffer given to from_chars
|
||||
// - __n the number of elements in the buffer
|
||||
// - __offset where to start parsing. The input can have an optional sign, the
|
||||
// offset starts after this sign.
|
||||
template <class _Tp>
|
||||
__fractional_constant_result<_Tp>
|
||||
__parse_fractional_decimal_constant(const char* __input, ptrdiff_t __n, ptrdiff_t __offset) {
|
||||
__fractional_constant_result<_Tp> __result;
|
||||
|
||||
const _Tp __mantissa_truncate_threshold = numeric_limits<_Tp>::max() / 10;
|
||||
bool __fraction = false;
|
||||
for (; __offset < __n; ++__offset) {
|
||||
if (std::isdigit(__input[__offset])) {
|
||||
__result.__is_valid = true;
|
||||
|
||||
uint32_t __digit = __input[__offset] - '0';
|
||||
if (__result.__mantissa < __mantissa_truncate_threshold) {
|
||||
__result.__mantissa = (__result.__mantissa * 10) + __digit;
|
||||
if (__fraction)
|
||||
--__result.__exponent;
|
||||
} else {
|
||||
if (__digit > 0)
|
||||
__result.__truncated = true;
|
||||
if (!__fraction)
|
||||
++__result.__exponent;
|
||||
}
|
||||
} else if (__input[__offset] == '.') {
|
||||
if (__fraction)
|
||||
break; // this means that __input[__offset] points to a second decimal point, ending the number.
|
||||
|
||||
__fraction = true;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
__result.__offset = __offset;
|
||||
return __result;
|
||||
}
|
||||
|
||||
// Implements from_chars for decimal floating-point values.
|
||||
// __first forwarded from from_chars
|
||||
// __last forwarded from from_chars
|
||||
// __value forwarded from from_chars
|
||||
// __fmt forwarded from from_chars
|
||||
// __ptr the start of the buffer to parse. This is after the optional sign character.
|
||||
// __negative should __value be set to a negative value?
|
||||
template <floating_point _Fp>
|
||||
__from_chars_result<_Fp> __from_chars_floating_point_decimal(
|
||||
const char* const __first, const char* __last, chars_format __fmt, const char* __ptr, bool __negative) {
|
||||
ptrdiff_t __n = __last - __first;
|
||||
ptrdiff_t __offset = __ptr - __first;
|
||||
|
||||
auto __fractional =
|
||||
std::__parse_fractional_decimal_constant<typename _Floating_type_traits<_Fp>::_Uint_type>(__first, __n, __offset);
|
||||
if (!__fractional.__is_valid)
|
||||
return {_Fp{0}, 0, errc::invalid_argument};
|
||||
|
||||
__offset = __fractional.__offset;
|
||||
|
||||
// LWG3456 Pattern used by std::from_chars is underspecified
|
||||
// This changes fixed to ignore a possible exponent instead of making its
|
||||
// existance an error.
|
||||
int __exponent;
|
||||
if (__fmt == chars_format::fixed) {
|
||||
__exponent =
|
||||
std::__merge_exponents(__fractional.__exponent, 0, LIBC_NAMESPACE::shared::FPBits<_Fp>::MAX_BIASED_EXPONENT);
|
||||
} else {
|
||||
auto __parsed_exponent = std::__parse_exponent(__first, __n, __offset, 'e');
|
||||
if (__fmt == chars_format::scientific && !__parsed_exponent.__present) {
|
||||
// [charconv.from.chars]/6.2 if fmt has chars_format::scientific set but not chars_format::fixed,
|
||||
// the otherwise optional exponent part shall appear;
|
||||
return {_Fp{0}, 0, errc::invalid_argument};
|
||||
}
|
||||
|
||||
__offset = __parsed_exponent.__offset;
|
||||
__exponent = std::__merge_exponents(
|
||||
__fractional.__exponent, __parsed_exponent.__value, LIBC_NAMESPACE::shared::FPBits<_Fp>::MAX_BIASED_EXPONENT);
|
||||
}
|
||||
|
||||
__from_chars_result<_Fp> __result{_Fp{0}, __offset, {}};
|
||||
LIBC_NAMESPACE::shared::ExpandedFloat<_Fp> __expanded_float = {0, 0};
|
||||
if (__fractional.__mantissa != 0) {
|
||||
// This function expects to parse a positive value. This means it does not
|
||||
// take a __first, __n as arguments, since __first points to '-' for
|
||||
// negative values.
|
||||
auto __temp = LIBC_NAMESPACE::shared::decimal_exp_to_float<_Fp>(
|
||||
{__fractional.__mantissa, __exponent},
|
||||
__fractional.__truncated,
|
||||
LIBC_NAMESPACE::shared::RoundDirection::Nearest,
|
||||
__ptr,
|
||||
__last - __ptr);
|
||||
__expanded_float = __temp.num;
|
||||
if (__temp.error == ERANGE) {
|
||||
__result.__ec = errc::result_out_of_range;
|
||||
}
|
||||
}
|
||||
|
||||
return std::__calculate_result(__expanded_float.mantissa, __expanded_float.exponent, __negative, __result);
|
||||
}
|
||||
|
||||
template <floating_point _Fp>
|
||||
__from_chars_result<_Fp>
|
||||
__from_chars_floating_point_impl(const char* const __first, const char* __last, chars_format __fmt) {
|
||||
if (__first == __last) [[unlikely]]
|
||||
return {_Fp{0}, 0, errc::invalid_argument};
|
||||
|
||||
const char* __ptr = __first;
|
||||
bool __negative = *__ptr == '-';
|
||||
if (__negative) {
|
||||
++__ptr;
|
||||
if (__ptr == __last) [[unlikely]]
|
||||
return {_Fp{0}, 0, errc::invalid_argument};
|
||||
}
|
||||
|
||||
// [charconv.from.chars]
|
||||
// [Note 1: If the pattern allows for an optional sign, but the string has
|
||||
// no digit characters following the sign, no characters match the pattern.
|
||||
// -- end note]
|
||||
// This is true for integrals, floating point allows -.0
|
||||
|
||||
// [charconv.from.chars]/6.2
|
||||
// if fmt has chars_format::scientific set but not chars_format::fixed, the
|
||||
// otherwise optional exponent part shall appear;
|
||||
// Since INF/NAN do not have an exponent this value is not valid.
|
||||
//
|
||||
// LWG3456 Pattern used by std::from_chars is underspecified
|
||||
// Does not address this point, but proposed option B does solve this issue,
|
||||
// Both MSVC STL and libstdc++ implement this this behaviour.
|
||||
switch (std::tolower(*__ptr)) {
|
||||
case 'i':
|
||||
return std::__from_chars_floating_point_inf<_Fp>(__first, __last, __ptr + 1, __negative);
|
||||
case 'n':
|
||||
if constexpr (numeric_limits<_Fp>::has_quiet_NaN)
|
||||
// NOTE: The pointer passed here will be parsed in the default C locale.
|
||||
// This is standard behavior (see https://eel.is/c++draft/charconv.from.chars), but may be unexpected.
|
||||
return std::__from_chars_floating_point_nan<_Fp>(__first, __last, __ptr + 1, __negative);
|
||||
return {_Fp{0}, 0, errc::invalid_argument};
|
||||
}
|
||||
|
||||
if (__fmt == chars_format::hex)
|
||||
return std::__from_chars_floating_point_hex<_Fp>(__first, __last, __ptr, __negative);
|
||||
|
||||
return std::__from_chars_floating_point_decimal<_Fp>(__first, __last, __fmt, __ptr, __negative);
|
||||
}
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif //_LIBCPP_SRC_INCLUDE_FROM_CHARS_FLOATING_POINT_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -45,6 +45,7 @@
|
||||
#include "float_hex_precision_to_chars_test_cases.hpp"
|
||||
#include "float_scientific_precision_to_chars_test_cases.hpp"
|
||||
#include "float_to_chars_test_cases.hpp"
|
||||
#include "floating_point_test_cases.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -589,8 +590,8 @@ void test_floating_prefix(const conditional_t<IsDouble, std::uint64_t, std::uint
|
||||
// "-1.2345678901234567e-100" or "-1.23456789e-10"
|
||||
constexpr std::size_t buffer_size = IsDouble ? 24 : 15;
|
||||
char buffer[buffer_size];
|
||||
// TODO Enable once std::from_chars has floating point support.
|
||||
#if 0
|
||||
|
||||
#ifdef TEST_HAS_FROM_CHARS_FLOATING_POINT
|
||||
FloatingType val;
|
||||
#endif
|
||||
|
||||
@@ -614,8 +615,7 @@ void test_floating_prefix(const conditional_t<IsDouble, std::uint64_t, std::uint
|
||||
{
|
||||
const auto to_result = to_chars(buffer, end(buffer), input, chars_format::scientific);
|
||||
assert_message_bits(to_result.ec == errc{}, "to_result.ec", bits);
|
||||
// TODO Enable once std::from_chars has floating point support.
|
||||
#if 0
|
||||
#ifdef TEST_HAS_FROM_CHARS_FLOATING_POINT
|
||||
const char* const last = to_result.ptr;
|
||||
|
||||
const auto from_result = from_chars(buffer, last, val);
|
||||
@@ -623,7 +623,7 @@ void test_floating_prefix(const conditional_t<IsDouble, std::uint64_t, std::uint
|
||||
assert_message_bits(from_result.ptr == last, "from_result.ptr", bits);
|
||||
assert_message_bits(from_result.ec == errc{}, "from_result.ec", bits);
|
||||
assert_message_bits(_Bit_cast<UIntType>(val) == bits, "round-trip", bits);
|
||||
#endif
|
||||
#endif // TEST_HAS_FROM_CHARS_FLOATING_POINT
|
||||
}
|
||||
|
||||
{
|
||||
@@ -656,8 +656,8 @@ void test_floating_hex_prefix(const conditional_t<IsDouble, std::uint64_t, std::
|
||||
// "-1.fffffffffffffp+1023" or "-1.fffffep+127"
|
||||
constexpr std::size_t buffer_size = IsDouble ? 22 : 14;
|
||||
char buffer[buffer_size];
|
||||
// TODO Enable once std::from_chars has floating point support.
|
||||
#if 0
|
||||
|
||||
#ifdef TEST_HAS_FROM_CHARS_FLOATING_POINT
|
||||
FloatingType val;
|
||||
#endif
|
||||
|
||||
@@ -667,8 +667,8 @@ void test_floating_hex_prefix(const conditional_t<IsDouble, std::uint64_t, std::
|
||||
|
||||
const auto to_result = to_chars(buffer, end(buffer), input, chars_format::hex);
|
||||
assert_message_bits(to_result.ec == errc{}, "(hex) to_result.ec", bits);
|
||||
// TODO Enable once std::from_chars has floating point support.
|
||||
#if 0
|
||||
|
||||
#ifdef TEST_HAS_FROM_CHARS_FLOATING_POINT
|
||||
const char* const last = to_result.ptr;
|
||||
|
||||
const auto from_result = from_chars(buffer, last, val, chars_format::hex);
|
||||
@@ -676,7 +676,7 @@ void test_floating_hex_prefix(const conditional_t<IsDouble, std::uint64_t, std::
|
||||
assert_message_bits(from_result.ptr == last, "(hex) from_result.ptr", bits);
|
||||
assert_message_bits(from_result.ec == errc{}, "(hex) from_result.ec", bits);
|
||||
assert_message_bits(_Bit_cast<UIntType>(val) == bits, "(hex) round-trip", bits);
|
||||
#endif
|
||||
#endif // TEST_HAS_FROM_CHARS_FLOATING_POINT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -786,8 +786,7 @@ void test_floating_prefixes(mt19937_64& mt64) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Enable once std::from_chars has floating point support.
|
||||
#if 0
|
||||
#ifdef TEST_HAS_FROM_CHARS_FLOATING_POINT
|
||||
template <typename T>
|
||||
void test_floating_from_chars(const chars_format fmt) {
|
||||
test_from_chars<T>("", fmt, 0, inv_arg); // no characters
|
||||
@@ -855,11 +854,13 @@ void test_floating_from_chars(const chars_format fmt) {
|
||||
|
||||
// The UCRT considers indeterminate NaN to be negative quiet NaN with no payload bits set.
|
||||
// It parses "nan(ind)" and "-nan(ind)" identically.
|
||||
# ifdef _MSC_VER
|
||||
test_from_chars<T>("nan(InD)", fmt, 8, errc{}, -qnan);
|
||||
test_from_chars<T>("-nan(InD)", fmt, 9, errc{}, -qnan);
|
||||
|
||||
test_from_chars<T>("nan(SnAn)", fmt, 9, errc{}, nullopt, TestFromCharsMode::SignalingNaN);
|
||||
test_from_chars<T>("-nan(SnAn)", fmt, 10, errc{}, nullopt, TestFromCharsMode::SignalingNaN);
|
||||
# endif
|
||||
|
||||
switch (fmt) {
|
||||
case chars_format::general:
|
||||
@@ -941,7 +942,7 @@ void test_floating_from_chars(const chars_format fmt) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // TEST_HAS_FROM_CHARS_FLOATING_POINT
|
||||
|
||||
template <typename T>
|
||||
void test_floating_to_chars(
|
||||
@@ -953,13 +954,11 @@ void test_floating_to_chars(
|
||||
void all_floating_tests(mt19937_64& mt64) {
|
||||
test_floating_prefixes(mt64);
|
||||
|
||||
// TODO Enable once std::from_chars has floating point support.
|
||||
#if 0
|
||||
#ifdef TEST_HAS_FROM_CHARS_FLOATING_POINT
|
||||
for (const auto& fmt : {chars_format::general, chars_format::scientific, chars_format::fixed, chars_format::hex}) {
|
||||
test_floating_from_chars<float>(fmt);
|
||||
test_floating_from_chars<double>(fmt);
|
||||
}
|
||||
|
||||
// Test rounding.
|
||||
|
||||
// See float_from_chars_test_cases.hpp in this directory.
|
||||
@@ -993,7 +992,8 @@ void all_floating_tests(mt19937_64& mt64) {
|
||||
for (const auto& p : floating_point_test_cases_double) {
|
||||
test_from_chars<double>(p.first, chars_format::general, strlen(p.first), errc{}, _Bit_cast<double>(p.second));
|
||||
}
|
||||
#endif
|
||||
#endif // TEST_HAS_FROM_CHARS_FLOATING_POINT
|
||||
|
||||
// See float_to_chars_test_cases.hpp in this directory.
|
||||
for (const auto& t : float_to_chars_test_cases) {
|
||||
if (t.fmt == chars_format{}) {
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14
|
||||
|
||||
// TODO Investigate why this fails
|
||||
// UNSUPPORTED: windows
|
||||
|
||||
// to_chars requires functions in the dylib that have not been introduced in older
|
||||
// versions of the dylib on macOS.
|
||||
// XFAIL: availability-fp_to_chars-missing
|
||||
@@ -22,6 +25,7 @@
|
||||
// <charconv>
|
||||
|
||||
#include <type_traits>
|
||||
#include "test_macros.h"
|
||||
|
||||
// Work-around for sprintf_s's usage in the Microsoft tests.
|
||||
#ifndef _WIN32
|
||||
|
||||
@@ -317,6 +317,8 @@ auto all_unsigned = type_list<
|
||||
>();
|
||||
auto integrals = concat(all_signed, all_unsigned);
|
||||
|
||||
auto all_floats = type_list< float, double >(); //TODO: Add long double
|
||||
|
||||
template <template <typename> class Fn, typename... Ts>
|
||||
TEST_CONSTEXPR_CXX23 void
|
||||
run(type_list<Ts...>)
|
||||
|
||||
@@ -262,6 +262,10 @@
|
||||
|
||||
#define TEST_IGNORE_NODISCARD (void)
|
||||
|
||||
#if !defined(_LIBCPP_VERSION) || _LIBCPP_AVAILABILITY_HAS_FROM_CHARS_FLOATING_POINT
|
||||
# define TEST_HAS_FROM_CHARS_FLOATING_POINT
|
||||
#endif
|
||||
|
||||
namespace test_macros_detail {
|
||||
template <class T, class U>
|
||||
struct is_same { enum { value = 0};} ;
|
||||
|
||||
@@ -795,4 +795,12 @@ DEFAULT_FEATURES += [
|
||||
cfg.available_features,
|
||||
),
|
||||
),
|
||||
# Tests that require std::from_chars(floating-point) in the built library
|
||||
Feature(
|
||||
name="availability-fp_from_chars-missing",
|
||||
when=lambda cfg: BooleanExpression.evaluate(
|
||||
"!libcpp-has-no-availability-markup && (stdlib=apple-libc++ && !_target-has-llvm-20)",
|
||||
cfg.available_features,
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
14
runtimes/cmake/Modules/FindLibcCommonUtils.cmake
Normal file
14
runtimes/cmake/Modules/FindLibcCommonUtils.cmake
Normal file
@@ -0,0 +1,14 @@
|
||||
#===--------------------------------------------------------------------===//
|
||||
#
|
||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
# See https://llvm.org/LICENSE.txt for details.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
#===--------------------------------------------------------------------===//
|
||||
|
||||
add_library(llvm-libc-common-utilities INTERFACE)
|
||||
# TODO: Reorganize the libc shared section so that it can be included without
|
||||
# adding the root "libc" directory to the include path.
|
||||
target_include_directories(llvm-libc-common-utilities INTERFACE ${CMAKE_CURRENT_LIST_DIR}/../../../libc)
|
||||
target_compile_definitions(llvm-libc-common-utilities INTERFACE LIBC_NAMESPACE=__llvm_libc_common_utils)
|
||||
target_compile_features(llvm-libc-common-utilities INTERFACE cxx_std_17)
|
||||
@@ -1420,6 +1420,19 @@ libc_support_library(
|
||||
],
|
||||
)
|
||||
|
||||
########################## externally shared targets ###########################
|
||||
|
||||
libc_support_library(
|
||||
name = "libc_external_common",
|
||||
hdrs = glob(["shared/*.h"]),
|
||||
deps = [
|
||||
":__support_common",
|
||||
":__support_fputil_fp_bits",
|
||||
":__support_str_to_float",
|
||||
":__support_str_to_integer",
|
||||
],
|
||||
)
|
||||
|
||||
############################### errno targets ################################
|
||||
|
||||
libc_function(
|
||||
|
||||
Reference in New Issue
Block a user