forked from OSchip/llvm-project
[libc++] Implements constexpr <charconv>.
Implements: - P2291R3 Add Constexpr Modifiers to Functions to_chars and from_chars for Integral Types in <charconv> Header Reviewed By: #libc, ldionne Differential Revision: https://reviews.llvm.org/D131317
This commit is contained in:
parent
261b5abf72
commit
a1e13a80d0
|
@ -310,6 +310,8 @@ Status
|
|||
------------------------------------------------- -----------------
|
||||
``__cpp_lib_constexpr_bitset`` ``202207L``
|
||||
------------------------------------------------- -----------------
|
||||
``__cpp_lib_constexpr_charconv`` ``202207L``
|
||||
------------------------------------------------- -----------------
|
||||
``__cpp_lib_constexpr_cmath`` *unimplemented*
|
||||
------------------------------------------------- -----------------
|
||||
``__cpp_lib_constexpr_memory`` ``202202L``
|
||||
|
|
|
@ -42,6 +42,8 @@ Implemented Papers
|
|||
- P2445R1 - ``std::forward_like``
|
||||
- P2273R3 - Making ``std::unique_ptr`` constexpr
|
||||
- P0591R4 - Utility functions to implement uses-allocator construction
|
||||
- P2291R3 - Add Constexpr Modifiers to Functions ``to_chars`` and
|
||||
``from_chars`` for Integral Types in ``<charconv>`` Header
|
||||
|
||||
Improvements and New Features
|
||||
-----------------------------
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
"`P2165R4 <https://wg21.link/P2165R4>`__","LWG","Compatibility between ``tuple``, ``pair`` and ``tuple-like`` objects","July 2022","",""
|
||||
"`P2278R4 <https://wg21.link/P2278R4>`__","LWG","``cbegin`` should always return a constant iterator","July 2022","",""
|
||||
"`P2286R8 <https://wg21.link/P2286R8>`__","LWG","Formatting Ranges","July 2022","",""
|
||||
"`P2291R3 <https://wg21.link/P2291R3>`__","LWG","Add Constexpr Modifiers to Functions ``to_chars`` and ``from_chars`` for Integral Types in ``<charconv>`` Header","July 2022","|In Progress|",""
|
||||
"`P2291R3 <https://wg21.link/P2291R3>`__","LWG","Add Constexpr Modifiers to Functions ``to_chars`` and ``from_chars`` for Integral Types in ``<charconv>`` Header","July 2022","|Complete|","16.0"
|
||||
"`P2302R4 <https://wg21.link/P2302R4>`__","LWG","``std::ranges::contains``","July 2022","",""
|
||||
"`P2322R6 <https://wg21.link/P2322R6>`__","LWG","``ranges::fold``","July 2022","",""
|
||||
"`P2374R4 <https://wg21.link/P2374R4>`__","LWG","``views::cartesian_product``","July 2022","",""
|
||||
|
|
|
|
@ -23,34 +23,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD
|
|||
|
||||
namespace __itoa {
|
||||
|
||||
/// Contains the charconv helper tables.
|
||||
///
|
||||
/// In C++17 these could be inline constexpr variable, but libc++ supports
|
||||
/// charconv for integrals in C++11 mode.
|
||||
template <class = void>
|
||||
struct __table {
|
||||
static const char __base_2_lut[64];
|
||||
static const char __base_8_lut[128];
|
||||
static const char __base_16_lut[512];
|
||||
|
||||
static const uint32_t __pow10_32[10];
|
||||
static const uint64_t __pow10_64[20];
|
||||
# ifndef _LIBCPP_HAS_NO_INT128
|
||||
// TODO FMT Reduce the number of entries in this table.
|
||||
static const __uint128_t __pow10_128[40];
|
||||
static const int __pow10_128_offset = 0;
|
||||
# endif
|
||||
static const char __digits_base_10[200];
|
||||
};
|
||||
|
||||
template <class _Tp>
|
||||
const char __table<_Tp>::__base_2_lut[64] = {
|
||||
inline constexpr char __base_2_lut[64] = {
|
||||
'0', '0', '0', '0', '0', '0', '0', '1', '0', '0', '1', '0', '0', '0', '1', '1', '0', '1', '0', '0', '0', '1',
|
||||
'0', '1', '0', '1', '1', '0', '0', '1', '1', '1', '1', '0', '0', '0', '1', '0', '0', '1', '1', '0', '1', '0',
|
||||
'1', '0', '1', '1', '1', '1', '0', '0', '1', '1', '0', '1', '1', '1', '1', '0', '1', '1', '1', '1'};
|
||||
|
||||
template <class _Tp>
|
||||
const char __table<_Tp>::__base_8_lut[128] = {
|
||||
inline constexpr char __base_8_lut[128] = {
|
||||
'0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '1', '0', '1', '1', '1', '2',
|
||||
'1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5',
|
||||
'2', '6', '2', '7', '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '4', '0',
|
||||
|
@ -58,8 +36,7 @@ const char __table<_Tp>::__base_8_lut[128] = {
|
|||
'5', '4', '5', '5', '5', '6', '5', '7', '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6',
|
||||
'6', '7', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7'};
|
||||
|
||||
template <class _Tp>
|
||||
const char __table<_Tp>::__base_16_lut[512] = {
|
||||
inline constexpr char __base_16_lut[512] = {
|
||||
'0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9', '0', 'a', '0',
|
||||
'b', '0', 'c', '0', 'd', '0', 'e', '0', 'f', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6',
|
||||
'1', '7', '1', '8', '1', '9', '1', 'a', '1', 'b', '1', 'c', '1', 'd', '1', 'e', '1', 'f', '2', '0', '2', '1', '2',
|
||||
|
@ -84,13 +61,11 @@ const char __table<_Tp>::__base_16_lut[512] = {
|
|||
'1', 'f', '2', 'f', '3', 'f', '4', 'f', '5', 'f', '6', 'f', '7', 'f', '8', 'f', '9', 'f', 'a', 'f', 'b', 'f', 'c',
|
||||
'f', 'd', 'f', 'e', 'f', 'f'};
|
||||
|
||||
template <class _Tp>
|
||||
const uint32_t __table<_Tp>::__pow10_32[10] = {
|
||||
inline constexpr uint32_t __pow10_32[10] = {
|
||||
UINT32_C(0), UINT32_C(10), UINT32_C(100), UINT32_C(1000), UINT32_C(10000),
|
||||
UINT32_C(100000), UINT32_C(1000000), UINT32_C(10000000), UINT32_C(100000000), UINT32_C(1000000000)};
|
||||
|
||||
template <class _Tp>
|
||||
const uint64_t __table<_Tp>::__pow10_64[20] = {UINT64_C(0),
|
||||
inline constexpr uint64_t __pow10_64[20] = {UINT64_C(0),
|
||||
UINT64_C(10),
|
||||
UINT64_C(100),
|
||||
UINT64_C(1000),
|
||||
|
@ -112,8 +87,8 @@ const uint64_t __table<_Tp>::__pow10_64[20] = {UINT64_C(0),
|
|||
UINT64_C(10000000000000000000)};
|
||||
|
||||
# ifndef _LIBCPP_HAS_NO_INT128
|
||||
template <class _Tp>
|
||||
const __uint128_t __table<_Tp>::__pow10_128[40] = {
|
||||
inline constexpr int __pow10_128_offset = 0;
|
||||
inline constexpr __uint128_t __pow10_128[40] = {
|
||||
UINT64_C(0),
|
||||
UINT64_C(10),
|
||||
UINT64_C(100),
|
||||
|
@ -156,8 +131,7 @@ const __uint128_t __table<_Tp>::__pow10_128[40] = {
|
|||
(__uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(10000000000000000000)) * 10};
|
||||
# endif
|
||||
|
||||
template <class _Tp>
|
||||
const char __table<_Tp>::__digits_base_10[200] = {
|
||||
inline constexpr char __digits_base_10[200] = {
|
||||
// clang-format off
|
||||
'0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
|
||||
'1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
|
||||
|
|
|
@ -29,50 +29,50 @@ _LIBCPP_BEGIN_NAMESPACE_STD
|
|||
|
||||
namespace __itoa {
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI inline char* __append1(char* __first, uint32_t __value) noexcept {
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __append1(char* __first, uint32_t __value) noexcept {
|
||||
*__first = '0' + static_cast<char>(__value);
|
||||
return __first + 1;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI inline char* __append2(char* __first, uint32_t __value) noexcept {
|
||||
return std::copy_n(&__table<>::__digits_base_10[__value * 2], 2, __first);
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __append2(char* __first, uint32_t __value) noexcept {
|
||||
return std::copy_n(&__digits_base_10[__value * 2], 2, __first);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI inline char* __append3(char* __first, uint32_t __value) noexcept {
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __append3(char* __first, uint32_t __value) noexcept {
|
||||
return __itoa::__append2(__itoa::__append1(__first, __value / 100), __value % 100);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI inline char* __append4(char* __first, uint32_t __value) noexcept {
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __append4(char* __first, uint32_t __value) noexcept {
|
||||
return __itoa::__append2(__itoa::__append2(__first, __value / 100), __value % 100);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI inline char* __append5(char* __first, uint32_t __value) noexcept {
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __append5(char* __first, uint32_t __value) noexcept {
|
||||
return __itoa::__append4(__itoa::__append1(__first, __value / 10000), __value % 10000);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI inline char* __append6(char* __first, uint32_t __value) noexcept {
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __append6(char* __first, uint32_t __value) noexcept {
|
||||
return __itoa::__append4(__itoa::__append2(__first, __value / 10000), __value % 10000);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI inline char* __append7(char* __first, uint32_t __value) noexcept {
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __append7(char* __first, uint32_t __value) noexcept {
|
||||
return __itoa::__append6(__itoa::__append1(__first, __value / 1000000), __value % 1000000);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI inline char* __append8(char* __first, uint32_t __value) noexcept {
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __append8(char* __first, uint32_t __value) noexcept {
|
||||
return __itoa::__append6(__itoa::__append2(__first, __value / 1000000), __value % 1000000);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI inline char* __append9(char* __first, uint32_t __value) noexcept {
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __append9(char* __first, uint32_t __value) noexcept {
|
||||
return __itoa::__append8(__itoa::__append1(__first, __value / 100000000), __value % 100000000);
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
_LIBCPP_HIDE_FROM_ABI char* __append10(char* __first, _Tp __value) noexcept {
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI char* __append10(char* __first, _Tp __value) noexcept {
|
||||
return __itoa::__append8(__itoa::__append2(__first, static_cast<uint32_t>(__value / 100000000)),
|
||||
static_cast<uint32_t>(__value % 100000000));
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI inline char* __base_10_u32(char* __first, uint32_t __value) noexcept {
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __base_10_u32(char* __first, uint32_t __value) noexcept {
|
||||
if (__value < 1000000) {
|
||||
if (__value < 10000) {
|
||||
if (__value < 100) {
|
||||
|
@ -107,7 +107,7 @@ _LIBCPP_HIDE_FROM_ABI inline char* __base_10_u32(char* __first, uint32_t __value
|
|||
return __itoa::__append10(__first, __value);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI inline char* __base_10_u64(char* __buffer, uint64_t __value) noexcept {
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __base_10_u64(char* __buffer, uint64_t __value) noexcept {
|
||||
if (__value <= UINT32_MAX)
|
||||
return __itoa::__base_10_u32(__buffer, static_cast<uint32_t>(__value));
|
||||
|
||||
|
@ -129,12 +129,12 @@ _LIBCPP_HIDE_FROM_ABI inline char* __base_10_u64(char* __buffer, uint64_t __valu
|
|||
/// \note The lookup table contains a partial set of exponents limiting the
|
||||
/// range that can be used. However the range is sufficient for
|
||||
/// \ref __base_10_u128.
|
||||
_LIBCPP_HIDE_FROM_ABI inline __uint128_t __pow_10(int __exp) noexcept {
|
||||
_LIBCPP_ASSERT(__exp >= __table<>::__pow10_128_offset, "Index out of bounds");
|
||||
return __table<>::__pow10_128[__exp - __table<>::__pow10_128_offset];
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline __uint128_t __pow_10(int __exp) noexcept {
|
||||
_LIBCPP_ASSERT(__exp >= __pow10_128_offset, "Index out of bounds");
|
||||
return __pow10_128[__exp - __pow10_128_offset];
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI inline char* __base_10_u128(char* __buffer, __uint128_t __value) noexcept {
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __base_10_u128(char* __buffer, __uint128_t __value) noexcept {
|
||||
_LIBCPP_ASSERT(
|
||||
__value > numeric_limits<uint64_t>::max(), "The optimizations for this algorithm fail when this isn't true.");
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@ namespace std {
|
|||
friend bool operator==(const to_chars_result&, const to_chars_result&) = default; // since C++20
|
||||
};
|
||||
|
||||
to_chars_result to_chars(char* first, char* last, see below value,
|
||||
int base = 10);
|
||||
constexpr to_chars_result to_chars(char* first, char* last, see below value,
|
||||
int base = 10); // constexpr since C++23
|
||||
to_chars_result to_chars(char* first, char* last, bool value,
|
||||
int base = 10) = delete;
|
||||
|
||||
|
@ -60,8 +60,8 @@ namespace std {
|
|||
friend bool operator==(const from_chars_result&, const from_chars_result&) = default; // since C++20
|
||||
};
|
||||
|
||||
from_chars_result from_chars(const char* first, const char* last,
|
||||
see below& value, int base = 10);
|
||||
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,
|
||||
|
@ -77,6 +77,7 @@ namespace std {
|
|||
|
||||
*/
|
||||
|
||||
#include <__algorithm/copy_n.h>
|
||||
#include <__assert> // all public C++ headers provide the assertion handler
|
||||
#include <__availability>
|
||||
#include <__bits>
|
||||
|
@ -88,6 +89,7 @@ namespace std {
|
|||
#include <__config>
|
||||
#include <__debug>
|
||||
#include <__errc>
|
||||
#include <__memory/addressof.h>
|
||||
#include <__type_traits/make_32_64_or_128_bit.h>
|
||||
#include <__utility/unreachable.h>
|
||||
#include <cmath> // for log2f
|
||||
|
@ -130,18 +132,18 @@ struct _LIBCPP_HIDDEN __traits_base<_Tp, __enable_if_t<sizeof(_Tp) <= sizeof(uin
|
|||
/// function requires its input to have at least one bit set the value of
|
||||
/// zero is set to one. This means the first element of the lookup table is
|
||||
/// zero.
|
||||
static _LIBCPP_HIDE_FROM_ABI int __width(_Tp __v)
|
||||
static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __width(_Tp __v)
|
||||
{
|
||||
auto __t = (32 - std::__libcpp_clz(static_cast<type>(__v | 1))) * 1233 >> 12;
|
||||
return __t - (__v < __table<>::__pow10_32[__t]) + 1;
|
||||
return __t - (__v < __itoa::__pow10_32[__t]) + 1;
|
||||
}
|
||||
|
||||
static _LIBCPP_HIDE_FROM_ABI char* __convert(char* __p, _Tp __v)
|
||||
static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI char* __convert(char* __p, _Tp __v)
|
||||
{
|
||||
return __itoa::__base_10_u32(__p, __v);
|
||||
}
|
||||
|
||||
static _LIBCPP_HIDE_FROM_ABI decltype(__table<>::__pow10_32)& __pow() { return __table<>::__pow10_32; }
|
||||
static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI decltype(__pow10_32)& __pow() { return __itoa::__pow10_32; }
|
||||
};
|
||||
|
||||
template <typename _Tp>
|
||||
|
@ -157,14 +159,14 @@ struct _LIBCPP_HIDDEN
|
|||
/// function requires its input to have at least one bit set the value of
|
||||
/// zero is set to one. This means the first element of the lookup table is
|
||||
/// zero.
|
||||
static _LIBCPP_HIDE_FROM_ABI int __width(_Tp __v) {
|
||||
static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __width(_Tp __v) {
|
||||
auto __t = (64 - std::__libcpp_clz(static_cast<type>(__v | 1))) * 1233 >> 12;
|
||||
return __t - (__v < __table<>::__pow10_64[__t]) + 1;
|
||||
return __t - (__v < __itoa::__pow10_64[__t]) + 1;
|
||||
}
|
||||
|
||||
static _LIBCPP_HIDE_FROM_ABI char* __convert(char* __p, _Tp __v) { return __itoa::__base_10_u64(__p, __v); }
|
||||
static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI char* __convert(char* __p, _Tp __v) { return __itoa::__base_10_u64(__p, __v); }
|
||||
|
||||
static _LIBCPP_HIDE_FROM_ABI decltype(__table<>::__pow10_64)& __pow() { return __table<>::__pow10_64; }
|
||||
static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI decltype(__pow10_64)& __pow() { return __itoa::__pow10_64; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -182,25 +184,25 @@ struct _LIBCPP_HIDDEN
|
|||
/// function requires its input to have at least one bit set the value of
|
||||
/// zero is set to one. This means the first element of the lookup table is
|
||||
/// zero.
|
||||
static _LIBCPP_HIDE_FROM_ABI int __width(_Tp __v) {
|
||||
static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __width(_Tp __v) {
|
||||
_LIBCPP_ASSERT(__v > numeric_limits<uint64_t>::max(), "The optimizations for this algorithm fail when this isn't true.");
|
||||
// There's always a bit set in the upper 64-bits.
|
||||
auto __t = (128 - std::__libcpp_clz(static_cast<uint64_t>(__v >> 64))) * 1233 >> 12;
|
||||
_LIBCPP_ASSERT(__t >= __table<>::__pow10_128_offset, "Index out of bounds");
|
||||
_LIBCPP_ASSERT(__t >= __itoa::__pow10_128_offset, "Index out of bounds");
|
||||
// __t is adjusted since the lookup table misses the lower entries.
|
||||
return __t - (__v < __table<>::__pow10_128[__t - __table<>::__pow10_128_offset]) + 1;
|
||||
return __t - (__v < __itoa::__pow10_128[__t - __itoa::__pow10_128_offset]) + 1;
|
||||
}
|
||||
|
||||
static _LIBCPP_HIDE_FROM_ABI char* __convert(char* __p, _Tp __v) { return __itoa::__base_10_u128(__p, __v); }
|
||||
static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI char* __convert(char* __p, _Tp __v) { return __itoa::__base_10_u128(__p, __v); }
|
||||
|
||||
// TODO FMT This pow function should get an index.
|
||||
// By moving this to its own header it can be reused by the pow function in to_chars_base_10.
|
||||
static _LIBCPP_HIDE_FROM_ABI decltype(__table<>::__pow10_128)& __pow() { return __table<>::__pow10_128; }
|
||||
static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI decltype(__pow10_128)& __pow() { return __itoa::__pow10_128; }
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename _Tp>
|
||||
inline _LIBCPP_HIDE_FROM_ABI bool
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool
|
||||
__mul_overflowed(unsigned char __a, _Tp __b, unsigned char& __r)
|
||||
{
|
||||
auto __c = __a * __b;
|
||||
|
@ -209,7 +211,7 @@ __mul_overflowed(unsigned char __a, _Tp __b, unsigned char& __r)
|
|||
}
|
||||
|
||||
template <typename _Tp>
|
||||
inline _LIBCPP_HIDE_FROM_ABI bool
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool
|
||||
__mul_overflowed(unsigned short __a, _Tp __b, unsigned short& __r)
|
||||
{
|
||||
auto __c = __a * __b;
|
||||
|
@ -218,7 +220,7 @@ __mul_overflowed(unsigned short __a, _Tp __b, unsigned short& __r)
|
|||
}
|
||||
|
||||
template <typename _Tp>
|
||||
inline _LIBCPP_HIDE_FROM_ABI bool
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool
|
||||
__mul_overflowed(_Tp __a, _Tp __b, _Tp& __r)
|
||||
{
|
||||
static_assert(is_unsigned<_Tp>::value, "");
|
||||
|
@ -227,7 +229,7 @@ __mul_overflowed(_Tp __a, _Tp __b, _Tp& __r)
|
|||
|
||||
template <typename _Tp, typename _Up>
|
||||
inline _LIBCPP_HIDE_FROM_ABI bool
|
||||
__mul_overflowed(_Tp __a, _Up __b, _Tp& __r)
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 __mul_overflowed(_Tp __a, _Up __b, _Tp& __r)
|
||||
{
|
||||
return __mul_overflowed(__a, static_cast<_Tp>(__b), __r);
|
||||
}
|
||||
|
@ -240,7 +242,7 @@ struct _LIBCPP_HIDDEN __traits : __traits_base<_Tp>
|
|||
using typename __traits_base<_Tp>::type;
|
||||
|
||||
// precondition: at least one non-zero character available
|
||||
static _LIBCPP_HIDE_FROM_ABI char const*
|
||||
static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI char const*
|
||||
__read(char const* __p, char const* __ep, type& __a, type& __b)
|
||||
{
|
||||
type __cprod[digits];
|
||||
|
@ -261,7 +263,7 @@ struct _LIBCPP_HIDDEN __traits : __traits_base<_Tp>
|
|||
}
|
||||
|
||||
template <typename _It1, typename _It2, class _Up>
|
||||
static _LIBCPP_HIDE_FROM_ABI _Up
|
||||
static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _Up
|
||||
__inner_product(_It1 __first1, _It1 __last1, _It2 __first2, _Up __init)
|
||||
{
|
||||
for (; __first1 < __last1; ++__first1, ++__first2)
|
||||
|
@ -273,7 +275,7 @@ struct _LIBCPP_HIDDEN __traits : __traits_base<_Tp>
|
|||
} // namespace __itoa
|
||||
|
||||
template <typename _Tp>
|
||||
inline _LIBCPP_HIDE_FROM_ABI _Tp
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI _Tp
|
||||
__complement(_Tp __x)
|
||||
{
|
||||
static_assert(is_unsigned<_Tp>::value, "cast to unsigned first");
|
||||
|
@ -281,7 +283,7 @@ __complement(_Tp __x)
|
|||
}
|
||||
|
||||
template <typename _Tp>
|
||||
inline _LIBCPP_HIDE_FROM_ABI to_chars_result
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
|
||||
__to_chars_itoa(char* __first, char* __last, _Tp __value, true_type)
|
||||
{
|
||||
auto __x = __to_unsigned_like(__value);
|
||||
|
@ -295,7 +297,7 @@ __to_chars_itoa(char* __first, char* __last, _Tp __value, true_type)
|
|||
}
|
||||
|
||||
template <typename _Tp>
|
||||
inline _LIBCPP_HIDE_FROM_ABI to_chars_result
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
|
||||
__to_chars_itoa(char* __first, char* __last, _Tp __value, false_type)
|
||||
{
|
||||
using __tx = __itoa::__traits<_Tp>;
|
||||
|
@ -309,7 +311,7 @@ __to_chars_itoa(char* __first, char* __last, _Tp __value, false_type)
|
|||
|
||||
# ifndef _LIBCPP_HAS_NO_INT128
|
||||
template <>
|
||||
inline _LIBCPP_HIDE_FROM_ABI to_chars_result
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
|
||||
__to_chars_itoa(char* __first, char* __last, __uint128_t __value, false_type)
|
||||
{
|
||||
// When the value fits in 64-bits use the 64-bit code path. This reduces
|
||||
|
@ -330,7 +332,7 @@ __to_chars_itoa(char* __first, char* __last, __uint128_t __value, false_type)
|
|||
#endif
|
||||
|
||||
template <typename _Tp>
|
||||
inline _LIBCPP_HIDE_FROM_ABI to_chars_result
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
|
||||
__to_chars_integral(char* __first, char* __last, _Tp __value, int __base,
|
||||
true_type)
|
||||
{
|
||||
|
@ -360,7 +362,7 @@ struct _LIBCPP_HIDDEN __integral<2> {
|
|||
}
|
||||
|
||||
template <typename _Tp>
|
||||
_LIBCPP_HIDE_FROM_ABI static to_chars_result __to_chars(char* __first, char* __last, _Tp __value) {
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI static to_chars_result __to_chars(char* __first, char* __last, _Tp __value) {
|
||||
ptrdiff_t __cap = __last - __first;
|
||||
int __n = __width(__value);
|
||||
if (__n > __cap)
|
||||
|
@ -373,7 +375,7 @@ struct _LIBCPP_HIDDEN __integral<2> {
|
|||
unsigned __c = __value % __divisor;
|
||||
__value /= __divisor;
|
||||
__p -= 4;
|
||||
std::memcpy(__p, &__table<>::__base_2_lut[4 * __c], 4);
|
||||
std::copy_n(&__base_2_lut[4 * __c], 4, __p);
|
||||
}
|
||||
do {
|
||||
unsigned __c = __value % 2;
|
||||
|
@ -395,7 +397,7 @@ struct _LIBCPP_HIDDEN __integral<8> {
|
|||
}
|
||||
|
||||
template <typename _Tp>
|
||||
_LIBCPP_HIDE_FROM_ABI static to_chars_result __to_chars(char* __first, char* __last, _Tp __value) {
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI static to_chars_result __to_chars(char* __first, char* __last, _Tp __value) {
|
||||
ptrdiff_t __cap = __last - __first;
|
||||
int __n = __width(__value);
|
||||
if (__n > __cap)
|
||||
|
@ -408,7 +410,7 @@ struct _LIBCPP_HIDDEN __integral<8> {
|
|||
unsigned __c = __value % __divisor;
|
||||
__value /= __divisor;
|
||||
__p -= 2;
|
||||
std::memcpy(__p, &__table<>::__base_8_lut[2 * __c], 2);
|
||||
std::copy_n(&__base_8_lut[2 * __c], 2, __p);
|
||||
}
|
||||
do {
|
||||
unsigned __c = __value % 8;
|
||||
|
@ -431,7 +433,7 @@ struct _LIBCPP_HIDDEN __integral<16> {
|
|||
}
|
||||
|
||||
template <typename _Tp>
|
||||
_LIBCPP_HIDE_FROM_ABI static to_chars_result __to_chars(char* __first, char* __last, _Tp __value) {
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI static to_chars_result __to_chars(char* __first, char* __last, _Tp __value) {
|
||||
ptrdiff_t __cap = __last - __first;
|
||||
int __n = __width(__value);
|
||||
if (__n > __cap)
|
||||
|
@ -444,7 +446,7 @@ struct _LIBCPP_HIDDEN __integral<16> {
|
|||
unsigned __c = __value % __divisor;
|
||||
__value /= __divisor;
|
||||
__p -= 2;
|
||||
std::memcpy(__p, &__table<>::__base_16_lut[2 * __c], 2);
|
||||
std::copy_n(&__base_16_lut[2 * __c], 2, __p);
|
||||
}
|
||||
if (__first != __last)
|
||||
do {
|
||||
|
@ -460,34 +462,34 @@ struct _LIBCPP_HIDDEN __integral<16> {
|
|||
|
||||
template <unsigned _Base, typename _Tp,
|
||||
typename enable_if<(sizeof(_Tp) >= sizeof(unsigned)), int>::type = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI int
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int
|
||||
__to_chars_integral_width(_Tp __value) {
|
||||
return __itoa::__integral<_Base>::__width(__value);
|
||||
}
|
||||
|
||||
template <unsigned _Base, typename _Tp,
|
||||
typename enable_if<(sizeof(_Tp) < sizeof(unsigned)), int>::type = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI int
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int
|
||||
__to_chars_integral_width(_Tp __value) {
|
||||
return std::__to_chars_integral_width<_Base>(static_cast<unsigned>(__value));
|
||||
}
|
||||
|
||||
template <unsigned _Base, typename _Tp,
|
||||
typename enable_if<(sizeof(_Tp) >= sizeof(unsigned)), int>::type = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI to_chars_result
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
|
||||
__to_chars_integral(char* __first, char* __last, _Tp __value) {
|
||||
return __itoa::__integral<_Base>::__to_chars(__first, __last, __value);
|
||||
}
|
||||
|
||||
template <unsigned _Base, typename _Tp,
|
||||
typename enable_if<(sizeof(_Tp) < sizeof(unsigned)), int>::type = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI to_chars_result
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
|
||||
__to_chars_integral(char* __first, char* __last, _Tp __value) {
|
||||
return std::__to_chars_integral<_Base>(__first, __last, static_cast<unsigned>(__value));
|
||||
}
|
||||
|
||||
template <typename _Tp>
|
||||
_LIBCPP_HIDE_FROM_ABI int
|
||||
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int
|
||||
__to_chars_integral_width(_Tp __value, unsigned __base) {
|
||||
_LIBCPP_ASSERT(__value >= 0, "The function requires a non-negative value.");
|
||||
|
||||
|
@ -514,7 +516,7 @@ __to_chars_integral_width(_Tp __value, unsigned __base) {
|
|||
}
|
||||
|
||||
template <typename _Tp>
|
||||
inline _LIBCPP_HIDE_FROM_ABI to_chars_result
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
|
||||
__to_chars_integral(char* __first, char* __last, _Tp __value, int __base,
|
||||
false_type)
|
||||
{
|
||||
|
@ -546,7 +548,7 @@ __to_chars_integral(char* __first, char* __last, _Tp __value, int __base,
|
|||
}
|
||||
|
||||
template <typename _Tp, typename enable_if<is_integral<_Tp>::value, int>::type = 0>
|
||||
inline _LIBCPP_HIDE_FROM_ABI to_chars_result
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
|
||||
to_chars(char* __first, char* __last, _Tp __value)
|
||||
{
|
||||
using _Type = __make_32_64_or_128_bit_t<_Tp>;
|
||||
|
@ -555,7 +557,7 @@ to_chars(char* __first, char* __last, _Tp __value)
|
|||
}
|
||||
|
||||
template <typename _Tp, typename enable_if<is_integral<_Tp>::value, int>::type = 0>
|
||||
inline _LIBCPP_HIDE_FROM_ABI to_chars_result
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI to_chars_result
|
||||
to_chars(char* __first, char* __last, _Tp __value, int __base)
|
||||
{
|
||||
_LIBCPP_ASSERT(2 <= __base && __base <= 36, "base not in [2, 36]");
|
||||
|
@ -565,7 +567,7 @@ to_chars(char* __first, char* __last, _Tp __value, int __base)
|
|||
}
|
||||
|
||||
template <typename _It, typename _Tp, typename _Fn, typename... _Ts>
|
||||
inline _LIBCPP_HIDE_FROM_ABI from_chars_result
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
|
||||
__sign_combinator(_It __first, _It __last, _Tp& __value, _Fn __f, _Ts... __args)
|
||||
{
|
||||
using __tl = numeric_limits<_Tp>;
|
||||
|
@ -588,7 +590,7 @@ __sign_combinator(_It __first, _It __last, _Tp& __value, _Fn __f, _Ts... __args)
|
|||
if (__x <= __complement(__to_unsigned_like(__tl::min())))
|
||||
{
|
||||
__x = __complement(__x);
|
||||
std::memcpy(&__value, &__x, sizeof(__x));
|
||||
std::copy_n(std::addressof(__x), 1, std::addressof(__value));
|
||||
return __r;
|
||||
}
|
||||
}
|
||||
|
@ -605,7 +607,7 @@ __sign_combinator(_It __first, _It __last, _Tp& __value, _Fn __f, _Ts... __args)
|
|||
}
|
||||
|
||||
template <typename _Tp>
|
||||
inline _LIBCPP_HIDE_FROM_ABI bool
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool
|
||||
__in_pattern(_Tp __c)
|
||||
{
|
||||
return '0' <= __c && __c <= '9';
|
||||
|
@ -616,11 +618,11 @@ struct _LIBCPP_HIDDEN __in_pattern_result
|
|||
bool __ok;
|
||||
int __val;
|
||||
|
||||
explicit _LIBCPP_HIDE_FROM_ABI operator bool() const { return __ok; }
|
||||
explicit _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI operator bool() const { return __ok; }
|
||||
};
|
||||
|
||||
template <typename _Tp>
|
||||
inline _LIBCPP_HIDE_FROM_ABI __in_pattern_result
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI __in_pattern_result
|
||||
__in_pattern(_Tp __c, int __base)
|
||||
{
|
||||
if (__base <= 10)
|
||||
|
@ -634,7 +636,7 @@ __in_pattern(_Tp __c, int __base)
|
|||
}
|
||||
|
||||
template <typename _It, typename _Tp, typename _Fn, typename... _Ts>
|
||||
inline _LIBCPP_HIDE_FROM_ABI from_chars_result
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
|
||||
__subject_seq_combinator(_It __first, _It __last, _Tp& __value, _Fn __f,
|
||||
_Ts... __args)
|
||||
{
|
||||
|
@ -671,7 +673,7 @@ __subject_seq_combinator(_It __first, _It __last, _Tp& __value, _Fn __f,
|
|||
}
|
||||
|
||||
template <typename _Tp, typename enable_if<is_unsigned<_Tp>::value, int>::type = 0>
|
||||
inline _LIBCPP_HIDE_FROM_ABI from_chars_result
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
|
||||
__from_chars_atoi(const char* __first, const char* __last, _Tp& __value)
|
||||
{
|
||||
using __tx = __itoa::__traits<_Tp>;
|
||||
|
@ -697,15 +699,34 @@ __from_chars_atoi(const char* __first, const char* __last, _Tp& __value)
|
|||
}
|
||||
|
||||
template <typename _Tp, typename enable_if<is_signed<_Tp>::value, int>::type = 0>
|
||||
inline _LIBCPP_HIDE_FROM_ABI from_chars_result
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
|
||||
__from_chars_atoi(const char* __first, const char* __last, _Tp& __value)
|
||||
{
|
||||
using __t = decltype(__to_unsigned_like(__value));
|
||||
return __sign_combinator(__first, __last, __value, __from_chars_atoi<__t>);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// Code used to generate __from_chars_log2f_lut.
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <format>
|
||||
|
||||
int main() {
|
||||
for (int i = 2; i <= 36; ++i)
|
||||
std::cout << std::format("{},\n", log2f(i));
|
||||
}
|
||||
*/
|
||||
/// log2f table for bases [2, 36].
|
||||
inline constexpr float __from_chars_log2f_lut[35] = {
|
||||
1, 1.5849625, 2, 2.321928, 2.5849626, 2.807355, 3, 3.169925, 3.321928,
|
||||
3.4594316, 3.5849626, 3.7004397, 3.807355, 3.9068906, 4, 4.087463, 4.169925, 4.2479277,
|
||||
4.321928, 4.3923173, 4.4594316, 4.523562, 4.5849624, 4.643856, 4.70044, 4.7548876, 4.807355,
|
||||
4.857981, 4.9068904, 4.9541965, 5, 5.044394, 5.087463, 5.129283, 5.169925};
|
||||
|
||||
template <typename _Tp, typename enable_if<is_unsigned<_Tp>::value, int>::type = 0>
|
||||
inline _LIBCPP_HIDE_FROM_ABI from_chars_result
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
|
||||
__from_chars_integral(const char* __first, const char* __last, _Tp& __value,
|
||||
int __base)
|
||||
{
|
||||
|
@ -717,7 +738,8 @@ __from_chars_integral(const char* __first, const char* __last, _Tp& __value,
|
|||
[](const char* __p, const char* __lastp, _Tp& __val,
|
||||
int __b) -> from_chars_result {
|
||||
using __tl = numeric_limits<_Tp>;
|
||||
auto __digits = __tl::digits / log2f(float(__b));
|
||||
// __base is always between 2 and 36 inclusive.
|
||||
auto __digits = __tl::digits / __from_chars_log2f_lut[__b - 2];
|
||||
_Tp __x = __in_pattern(*__p++, __b).__val, __y = 0;
|
||||
|
||||
for (int __i = 1; __p != __lastp; ++__i, ++__p)
|
||||
|
@ -752,7 +774,7 @@ __from_chars_integral(const char* __first, const char* __last, _Tp& __value,
|
|||
}
|
||||
|
||||
template <typename _Tp, typename enable_if<is_signed<_Tp>::value, int>::type = 0>
|
||||
inline _LIBCPP_HIDE_FROM_ABI from_chars_result
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
|
||||
__from_chars_integral(const char* __first, const char* __last, _Tp& __value,
|
||||
int __base)
|
||||
{
|
||||
|
@ -762,14 +784,14 @@ __from_chars_integral(const char* __first, const char* __last, _Tp& __value,
|
|||
}
|
||||
|
||||
template <typename _Tp, typename enable_if<is_integral<_Tp>::value, int>::type = 0>
|
||||
inline _LIBCPP_HIDE_FROM_ABI from_chars_result
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
|
||||
from_chars(const char* __first, const char* __last, _Tp& __value)
|
||||
{
|
||||
return __from_chars_atoi(__first, __last, __value);
|
||||
}
|
||||
|
||||
template <typename _Tp, typename enable_if<is_integral<_Tp>::value, int>::type = 0>
|
||||
inline _LIBCPP_HIDE_FROM_ABI from_chars_result
|
||||
inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI from_chars_result
|
||||
from_chars(const char* __first, const char* __last, _Tp& __value, int __base)
|
||||
{
|
||||
_LIBCPP_ASSERT(2 <= __base && __base <= 36, "base not in [2, 36]");
|
||||
|
|
|
@ -57,6 +57,7 @@ __cpp_lib_complex_udls 201309L <complex>
|
|||
__cpp_lib_concepts 202002L <concepts>
|
||||
__cpp_lib_constexpr_algorithms 201806L <algorithm>
|
||||
__cpp_lib_constexpr_bitset 202207L <bitset>
|
||||
__cpp_lib_constexpr_charconv 202207L <charconv>
|
||||
__cpp_lib_constexpr_cmath 202202L <cmath> <cstdlib>
|
||||
__cpp_lib_constexpr_complex 201711L <complex>
|
||||
__cpp_lib_constexpr_dynamic_alloc 201907L <memory>
|
||||
|
@ -384,6 +385,7 @@ __cpp_lib_void_t 201411L <type_traits>
|
|||
// # define __cpp_lib_bind_back 202202L
|
||||
# define __cpp_lib_byteswap 202110L
|
||||
# define __cpp_lib_constexpr_bitset 202207L
|
||||
# define __cpp_lib_constexpr_charconv 202207L
|
||||
// # define __cpp_lib_constexpr_cmath 202202L
|
||||
# undef __cpp_lib_constexpr_memory
|
||||
# define __cpp_lib_constexpr_memory 202202L
|
||||
|
|
|
@ -50,7 +50,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
|
|||
// In order to minimize the diff in the Ryu code between MSVC STL and libc++
|
||||
// the code uses the name __DIGIT_TABLE. In order to avoid code duplication it
|
||||
// reuses the table already available in libc++.
|
||||
inline constexpr auto& __DIGIT_TABLE = __itoa::__table<>::__digits_base_10;
|
||||
inline constexpr auto& __DIGIT_TABLE = __itoa::__digits_base_10;
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
|
|
|
@ -15,8 +15,9 @@
|
|||
|
||||
// Test the feature test macros defined by <charconv>
|
||||
|
||||
/* Constant Value
|
||||
__cpp_lib_to_chars 201611L [C++17]
|
||||
/* Constant Value
|
||||
__cpp_lib_constexpr_charconv 202207L [C++2b]
|
||||
__cpp_lib_to_chars 201611L [C++17]
|
||||
*/
|
||||
|
||||
#include <charconv>
|
||||
|
@ -24,18 +25,30 @@
|
|||
|
||||
#if TEST_STD_VER < 14
|
||||
|
||||
# ifdef __cpp_lib_constexpr_charconv
|
||||
# error "__cpp_lib_constexpr_charconv should not be defined before c++2b"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_to_chars
|
||||
# error "__cpp_lib_to_chars should not be defined before c++17"
|
||||
# endif
|
||||
|
||||
#elif TEST_STD_VER == 14
|
||||
|
||||
# ifdef __cpp_lib_constexpr_charconv
|
||||
# error "__cpp_lib_constexpr_charconv should not be defined before c++2b"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_to_chars
|
||||
# error "__cpp_lib_to_chars should not be defined before c++17"
|
||||
# endif
|
||||
|
||||
#elif TEST_STD_VER == 17
|
||||
|
||||
# ifdef __cpp_lib_constexpr_charconv
|
||||
# error "__cpp_lib_constexpr_charconv should not be defined before c++2b"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_to_chars
|
||||
# error "__cpp_lib_to_chars should be defined in c++17"
|
||||
|
@ -51,6 +64,10 @@
|
|||
|
||||
#elif TEST_STD_VER == 20
|
||||
|
||||
# ifdef __cpp_lib_constexpr_charconv
|
||||
# error "__cpp_lib_constexpr_charconv should not be defined before c++2b"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_to_chars
|
||||
# error "__cpp_lib_to_chars should be defined in c++20"
|
||||
|
@ -66,6 +83,13 @@
|
|||
|
||||
#elif TEST_STD_VER > 20
|
||||
|
||||
# ifndef __cpp_lib_constexpr_charconv
|
||||
# error "__cpp_lib_constexpr_charconv should be defined in c++2b"
|
||||
# endif
|
||||
# if __cpp_lib_constexpr_charconv != 202207L
|
||||
# error "__cpp_lib_constexpr_charconv should have the value 202207L in c++2b"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_to_chars
|
||||
# error "__cpp_lib_to_chars should be defined in c++2b"
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
__cpp_lib_concepts 202002L [C++20]
|
||||
__cpp_lib_constexpr_algorithms 201806L [C++20]
|
||||
__cpp_lib_constexpr_bitset 202207L [C++2b]
|
||||
__cpp_lib_constexpr_charconv 202207L [C++2b]
|
||||
__cpp_lib_constexpr_cmath 202202L [C++2b]
|
||||
__cpp_lib_constexpr_complex 201711L [C++20]
|
||||
__cpp_lib_constexpr_dynamic_alloc 201907L [C++20]
|
||||
|
@ -331,6 +332,10 @@
|
|||
# error "__cpp_lib_constexpr_bitset should not be defined before c++2b"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_constexpr_charconv
|
||||
# error "__cpp_lib_constexpr_charconv should not be defined before c++2b"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_constexpr_cmath
|
||||
# error "__cpp_lib_constexpr_cmath should not be defined before c++2b"
|
||||
# endif
|
||||
|
@ -967,6 +972,10 @@
|
|||
# error "__cpp_lib_constexpr_bitset should not be defined before c++2b"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_constexpr_charconv
|
||||
# error "__cpp_lib_constexpr_charconv should not be defined before c++2b"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_constexpr_cmath
|
||||
# error "__cpp_lib_constexpr_cmath should not be defined before c++2b"
|
||||
# endif
|
||||
|
@ -1699,6 +1708,10 @@
|
|||
# error "__cpp_lib_constexpr_bitset should not be defined before c++2b"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_constexpr_charconv
|
||||
# error "__cpp_lib_constexpr_charconv should not be defined before c++2b"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_constexpr_cmath
|
||||
# error "__cpp_lib_constexpr_cmath should not be defined before c++2b"
|
||||
# endif
|
||||
|
@ -2671,6 +2684,10 @@
|
|||
# error "__cpp_lib_constexpr_bitset should not be defined before c++2b"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_constexpr_charconv
|
||||
# error "__cpp_lib_constexpr_charconv should not be defined before c++2b"
|
||||
# endif
|
||||
|
||||
# ifdef __cpp_lib_constexpr_cmath
|
||||
# error "__cpp_lib_constexpr_cmath should not be defined before c++2b"
|
||||
# endif
|
||||
|
@ -3889,6 +3906,13 @@
|
|||
# error "__cpp_lib_constexpr_bitset should have the value 202207L in c++2b"
|
||||
# endif
|
||||
|
||||
# ifndef __cpp_lib_constexpr_charconv
|
||||
# error "__cpp_lib_constexpr_charconv should be defined in c++2b"
|
||||
# endif
|
||||
# if __cpp_lib_constexpr_charconv != 202207L
|
||||
# error "__cpp_lib_constexpr_charconv should have the value 202207L in c++2b"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_VERSION)
|
||||
# ifndef __cpp_lib_constexpr_cmath
|
||||
# error "__cpp_lib_constexpr_cmath should be defined in c++2b"
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
|
||||
// <charconv>
|
||||
|
||||
// from_chars_result from_chars(const char* first, const char* last,
|
||||
// Integral& value, int base = 10)
|
||||
// constexpr from_chars_result from_chars(const char* first, const char* last,
|
||||
// Integral& value, int base = 10)
|
||||
|
||||
#include <charconv>
|
||||
#include "test_macros.h"
|
||||
|
@ -20,7 +20,7 @@
|
|||
template <typename T>
|
||||
struct test_basics
|
||||
{
|
||||
void operator()()
|
||||
TEST_CONSTEXPR_CXX23 void operator()()
|
||||
{
|
||||
std::from_chars_result r;
|
||||
T x;
|
||||
|
@ -84,7 +84,7 @@ struct test_basics
|
|||
template <typename T>
|
||||
struct test_signed
|
||||
{
|
||||
void operator()()
|
||||
TEST_CONSTEXPR_CXX23 void operator()()
|
||||
{
|
||||
std::from_chars_result r;
|
||||
T x = 42;
|
||||
|
@ -135,10 +135,19 @@ struct test_signed
|
|||
}
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
TEST_CONSTEXPR_CXX23 bool test()
|
||||
{
|
||||
run<test_basics>(integrals);
|
||||
run<test_signed>(all_signed);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
#if TEST_STD_VER > 20
|
||||
static_assert(test());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
|
||||
// UNSUPPORTED: c++03, c++11, c++14
|
||||
|
||||
// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=12712420
|
||||
|
||||
// <charconv>
|
||||
|
||||
// from_chars_result from_chars(const char* first, const char* last,
|
||||
// Integral& value, int base = 10)
|
||||
// constexpr from_chars_result from_chars(const char* first, const char* last,
|
||||
// Integral& value, int base = 10)
|
||||
|
||||
#include <charconv>
|
||||
#include "test_macros.h"
|
||||
|
@ -22,7 +24,7 @@ struct test_basics : roundtrip_test_base<T>
|
|||
{
|
||||
using roundtrip_test_base<T>::test;
|
||||
|
||||
void operator()()
|
||||
TEST_CONSTEXPR_CXX23 void operator()()
|
||||
{
|
||||
test(0);
|
||||
test(42);
|
||||
|
@ -52,7 +54,7 @@ struct test_signed : roundtrip_test_base<T>
|
|||
{
|
||||
using roundtrip_test_base<T>::test;
|
||||
|
||||
void operator()()
|
||||
TEST_CONSTEXPR_CXX23 void operator()()
|
||||
{
|
||||
test(-1);
|
||||
test(-12);
|
||||
|
@ -73,10 +75,19 @@ struct test_signed : roundtrip_test_base<T>
|
|||
}
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
TEST_CONSTEXPR_CXX23 bool test()
|
||||
{
|
||||
run<test_basics>(integrals);
|
||||
run<test_signed>(all_signed);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
#if TEST_STD_VER > 20
|
||||
static_assert(test());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -9,38 +9,38 @@
|
|||
// UNSUPPORTED: c++03, c++11, c++14
|
||||
|
||||
// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=12712420
|
||||
// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=12712420
|
||||
// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=50000000
|
||||
|
||||
// <charconv>
|
||||
|
||||
// to_chars_result to_chars(char* first, char* last, Integral value,
|
||||
// int base = 10)
|
||||
// constexpr to_chars_result to_chars(char* first, char* last, Integral value,
|
||||
// int base = 10)
|
||||
|
||||
#include <charconv>
|
||||
#include "test_macros.h"
|
||||
#include "charconv_test_helpers.h"
|
||||
|
||||
#ifndef TEST_HAS_NO_INT128
|
||||
__uint128_t make_u128(__uint128_t a, uint64_t b) {
|
||||
TEST_CONSTEXPR_CXX23 __uint128_t make_u128(__uint128_t a, uint64_t b) {
|
||||
a *= 1000000000000000000UL;
|
||||
a *= 10;
|
||||
return a + b;
|
||||
}
|
||||
|
||||
__uint128_t make_u128(__uint128_t a, uint64_t b, uint64_t c) {
|
||||
TEST_CONSTEXPR_CXX23 __uint128_t make_u128(__uint128_t a, uint64_t b, uint64_t c) {
|
||||
a *= 10000000000000ULL;
|
||||
a += b;
|
||||
a *= 10000000000000ULL;
|
||||
return a + c;
|
||||
}
|
||||
|
||||
__int128_t make_i128(__int128_t a, int64_t b) {
|
||||
TEST_CONSTEXPR_CXX23 __int128_t make_i128(__int128_t a, int64_t b) {
|
||||
if (a < 0)
|
||||
return -make_u128(-a, b);
|
||||
return make_u128(a, b);
|
||||
}
|
||||
|
||||
__int128_t make_i128(__int128_t a, __int128_t b, int64_t c) {
|
||||
TEST_CONSTEXPR_CXX23 __int128_t make_i128(__int128_t a, __int128_t b, int64_t c) {
|
||||
if (a < 0)
|
||||
return -make_u128(-a, b, c);
|
||||
return make_u128(a, b, c);
|
||||
|
@ -53,7 +53,7 @@ struct test_basics : to_chars_test_base<T>
|
|||
using to_chars_test_base<T>::test;
|
||||
using to_chars_test_base<T>::test_value;
|
||||
|
||||
void operator()()
|
||||
TEST_CONSTEXPR_CXX23 void operator()()
|
||||
{
|
||||
test(0, "0");
|
||||
test(42, "42");
|
||||
|
@ -175,7 +175,7 @@ struct test_signed : to_chars_test_base<T>
|
|||
using to_chars_test_base<T>::test;
|
||||
using to_chars_test_base<T>::test_value;
|
||||
|
||||
void operator()()
|
||||
TEST_CONSTEXPR_CXX23 void operator()()
|
||||
{
|
||||
test(-1, "-1");
|
||||
test(-12, "-12");
|
||||
|
@ -289,10 +289,20 @@ struct test_signed : to_chars_test_base<T>
|
|||
}
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
TEST_CONSTEXPR_CXX23 bool test()
|
||||
{
|
||||
run<test_basics>(integrals);
|
||||
run<test_signed>(all_signed);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test();
|
||||
#if TEST_STD_VER > 20
|
||||
static_assert(test());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#ifndef SUPPORT_CHARCONV_TEST_HELPERS_H
|
||||
#define SUPPORT_CHARCONV_TEST_HELPERS_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <charconv>
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
|
@ -78,9 +79,8 @@ template <typename X>
|
|||
struct to_chars_test_base
|
||||
{
|
||||
template <typename T, size_t N, typename... Ts>
|
||||
void test(T v, char const (&expect)[N], Ts... args)
|
||||
TEST_CONSTEXPR_CXX23 void test(T v, char const (&expect)[N], Ts... args)
|
||||
{
|
||||
using std::to_chars;
|
||||
std::to_chars_result r;
|
||||
|
||||
constexpr size_t len = N - 1;
|
||||
|
@ -89,29 +89,29 @@ struct to_chars_test_base
|
|||
if (!fits_in<X>(v))
|
||||
return;
|
||||
|
||||
r = to_chars(buf, buf + len - 1, X(v), args...);
|
||||
r = std::to_chars(buf, buf + len - 1, X(v), args...);
|
||||
assert(r.ptr == buf + len - 1);
|
||||
assert(r.ec == std::errc::value_too_large);
|
||||
|
||||
r = to_chars(buf, buf + sizeof(buf), X(v), args...);
|
||||
r = std::to_chars(buf, buf + sizeof(buf), X(v), args...);
|
||||
assert(r.ptr == buf + len);
|
||||
assert(r.ec == std::errc{});
|
||||
assert(memcmp(buf, expect, len) == 0);
|
||||
assert(std::equal(buf, buf + len, expect));
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
void test_value(X v, Ts... args)
|
||||
TEST_CONSTEXPR_CXX23 void test_value(X v, Ts... args)
|
||||
{
|
||||
using std::to_chars;
|
||||
std::to_chars_result r;
|
||||
|
||||
// Poison the buffer for testing whether a successful std::to_chars
|
||||
// doesn't modify data beyond r.ptr.
|
||||
std::iota(buf, buf + sizeof(buf), char(1));
|
||||
r = to_chars(buf, buf + sizeof(buf), v, args...);
|
||||
// doesn't modify data beyond r.ptr. Use unsigned values to avoid
|
||||
// overflowing char when it's signed.
|
||||
std::iota(buf, buf + sizeof(buf), static_cast<unsigned char>(1));
|
||||
r = std::to_chars(buf, buf + sizeof(buf), v, args...);
|
||||
assert(r.ec == std::errc{});
|
||||
for (size_t i = r.ptr - buf; i < sizeof(buf); ++i)
|
||||
assert(buf[i] == static_cast<char>(i + 1));
|
||||
assert(static_cast<unsigned char>(buf[i]) == i + 1);
|
||||
*r.ptr = '\0';
|
||||
|
||||
#ifndef TEST_HAS_NO_INT128
|
||||
|
@ -126,42 +126,53 @@ struct to_chars_test_base
|
|||
}
|
||||
|
||||
auto ep = r.ptr - 1;
|
||||
r = to_chars(buf, ep, v, args...);
|
||||
r = std::to_chars(buf, ep, v, args...);
|
||||
assert(r.ptr == ep);
|
||||
assert(r.ec == std::errc::value_too_large);
|
||||
}
|
||||
|
||||
private:
|
||||
static long long fromchars_impl(char const* p, char const* ep, int base, true_type)
|
||||
static TEST_CONSTEXPR_CXX23 long long fromchars_impl(char const* p, char const* ep, int base, true_type)
|
||||
{
|
||||
char* last;
|
||||
auto r = strtoll(p, &last, base);
|
||||
long long r;
|
||||
if (TEST_IS_CONSTANT_EVALUATED)
|
||||
last = const_cast<char*>(std::from_chars(p, ep, r, base).ptr);
|
||||
else
|
||||
r = strtoll(p, &last, base);
|
||||
assert(last == ep);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static unsigned long long fromchars_impl(char const* p, char const* ep, int base, false_type)
|
||||
static TEST_CONSTEXPR_CXX23 unsigned long long fromchars_impl(char const* p, char const* ep, int base, false_type)
|
||||
{
|
||||
char* last;
|
||||
auto r = strtoull(p, &last, base);
|
||||
unsigned long long r;
|
||||
if (TEST_IS_CONSTANT_EVALUATED)
|
||||
last = const_cast<char*>(std::from_chars(p, ep, r, base).ptr);
|
||||
else
|
||||
r = strtoull(p, &last, base);
|
||||
assert(last == ep);
|
||||
|
||||
return r;
|
||||
}
|
||||
#ifndef TEST_HAS_NO_INT128
|
||||
static __int128_t fromchars128_impl(char const* p, char const* ep, int base, true_type)
|
||||
static TEST_CONSTEXPR_CXX23 __int128_t fromchars128_impl(char const* p, char const* ep, int base, true_type)
|
||||
{
|
||||
char* last;
|
||||
__int128_t r = strtoll(p, &last, base);
|
||||
if(errno != ERANGE) {
|
||||
assert(last == ep);
|
||||
return r;
|
||||
if (!TEST_IS_CONSTANT_EVALUATED) {
|
||||
char* last;
|
||||
__int128_t r = strtoll(p, &last, base);
|
||||
if(errno != ERANGE) {
|
||||
assert(last == ep);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
// When the value doesn't fit in a long long use from_chars. This is
|
||||
// not ideal since it does a round-trip test instead if using an
|
||||
// external source.
|
||||
__int128_t r;
|
||||
std::from_chars_result s = std::from_chars(p, ep, r, base);
|
||||
assert(s.ec == std::errc{});
|
||||
assert(s.ptr == ep);
|
||||
|
@ -169,15 +180,18 @@ private:
|
|||
return r;
|
||||
}
|
||||
|
||||
static __uint128_t fromchars128_impl(char const* p, char const* ep, int base, false_type)
|
||||
static TEST_CONSTEXPR_CXX23 __uint128_t fromchars128_impl(char const* p, char const* ep, int base, false_type)
|
||||
{
|
||||
char* last;
|
||||
__uint128_t r = strtoull(p, &last, base);
|
||||
if(errno != ERANGE) {
|
||||
assert(last == ep);
|
||||
return r;
|
||||
if (!TEST_IS_CONSTANT_EVALUATED) {
|
||||
char* last;
|
||||
__uint128_t r = strtoull(p, &last, base);
|
||||
if(errno != ERANGE) {
|
||||
assert(last == ep);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
__uint128_t r;
|
||||
std::from_chars_result s = std::from_chars(p, ep, r, base);
|
||||
assert(s.ec == std::errc{});
|
||||
assert(s.ptr == ep);
|
||||
|
@ -185,7 +199,7 @@ private:
|
|||
return r;
|
||||
}
|
||||
|
||||
static auto fromchars128_impl(char const* p, char const* ep, int base = 10)
|
||||
static TEST_CONSTEXPR_CXX23 auto fromchars128_impl(char const* p, char const* ep, int base = 10)
|
||||
-> decltype(fromchars128_impl(p, ep, base, std::is_signed<X>()))
|
||||
{
|
||||
return fromchars128_impl(p, ep, base, std::is_signed<X>());
|
||||
|
@ -193,7 +207,7 @@ private:
|
|||
|
||||
#endif
|
||||
|
||||
static auto fromchars_impl(char const* p, char const* ep, int base = 10)
|
||||
static TEST_CONSTEXPR_CXX23 auto fromchars_impl(char const* p, char const* ep, int base = 10)
|
||||
-> decltype(fromchars_impl(p, ep, base, std::is_signed<X>()))
|
||||
{
|
||||
return fromchars_impl(p, ep, base, std::is_signed<X>());
|
||||
|
@ -206,29 +220,27 @@ template <typename X>
|
|||
struct roundtrip_test_base
|
||||
{
|
||||
template <typename T, typename... Ts>
|
||||
void test(T v, Ts... args)
|
||||
TEST_CONSTEXPR_CXX23 void test(T v, Ts... args)
|
||||
{
|
||||
using std::from_chars;
|
||||
using std::to_chars;
|
||||
std::from_chars_result r2;
|
||||
std::to_chars_result r;
|
||||
X x = 0xc;
|
||||
|
||||
if (fits_in<X>(v))
|
||||
{
|
||||
r = to_chars(buf, buf + sizeof(buf), v, args...);
|
||||
r = std::to_chars(buf, buf + sizeof(buf), v, args...);
|
||||
assert(r.ec == std::errc{});
|
||||
|
||||
r2 = from_chars(buf, r.ptr, x, args...);
|
||||
r2 = std::from_chars(buf, r.ptr, x, args...);
|
||||
assert(r2.ptr == r.ptr);
|
||||
assert(x == X(v));
|
||||
}
|
||||
else
|
||||
{
|
||||
r = to_chars(buf, buf + sizeof(buf), v, args...);
|
||||
r = std::to_chars(buf, buf + sizeof(buf), v, args...);
|
||||
assert(r.ec == std::errc{});
|
||||
|
||||
r2 = from_chars(buf, r.ptr, x, args...);
|
||||
r2 = std::from_chars(buf, r.ptr, x, args...);
|
||||
|
||||
TEST_DIAGNOSTIC_PUSH
|
||||
TEST_MSVC_DIAGNOSTIC_IGNORED(4127) // conditional expression is constant
|
||||
|
@ -303,7 +315,7 @@ auto all_unsigned = type_list<
|
|||
auto integrals = concat(all_signed, all_unsigned);
|
||||
|
||||
template <template <typename> class Fn, typename... Ts>
|
||||
void
|
||||
TEST_CONSTEXPR_CXX23 void
|
||||
run(type_list<Ts...>)
|
||||
{
|
||||
int ls[sizeof...(Ts)] = {(Fn<Ts>{}(), 0)...};
|
||||
|
|
|
@ -218,6 +218,10 @@ feature_test_macros = [ add_version_header(x) for x in [
|
|||
"name": "__cpp_lib_constexpr_bitset",
|
||||
"values": { "c++2b": 202207 },
|
||||
"headers": ["bitset"],
|
||||
}, {
|
||||
"name": "__cpp_lib_constexpr_charconv",
|
||||
"values": { "c++2b": 202207 },
|
||||
"headers": ["charconv"],
|
||||
}, {
|
||||
"name": "__cpp_lib_constexpr_cmath",
|
||||
"values": { "c++2b": 202202 },
|
||||
|
|
Loading…
Reference in New Issue