diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -308,6 +308,8 @@ ------------------------------------------------- ----------------- ``__cpp_lib_byteswap`` ``202110L`` ------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_charconv`` ``202207L`` + ------------------------------------------------- ----------------- ``__cpp_lib_constexpr_cmath`` *unimplemented* ------------------------------------------------- ----------------- ``__cpp_lib_constexpr_typeinfo`` *unimplemented* diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -38,6 +38,8 @@ Implemented Papers ------------------ - P2499R0 - ``string_view`` range constructor should be ``explicit`` +- P2291R3 - Add Constexpr Modifiers to Functions ``to_chars`` and + ``from_chars`` for Integral Types in ```` Header Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv --- a/libcxx/docs/Status/Cxx2bPapers.csv +++ b/libcxx/docs/Status/Cxx2bPapers.csv @@ -63,7 +63,7 @@ "`P2165R4 `__","LWG","Compatibility between ``tuple``, ``pair`` and ``tuple-like`` objects","July 2022","","" "`P2278R4 `__","LWG","``cbegin`` should always return a constant iterator","July 2022","","" "`P2286R8 `__","LWG","Formatting Ranges","July 2022","","" -"`P2291R3 `__","LWG","Add Constexpr Modifiers to Functions ``to_chars`` and ``from_chars`` for Integral Types in ```` Header","July 2022","","" +"`P2291R3 `__","LWG","Add Constexpr Modifiers to Functions ``to_chars`` and ``from_chars`` for Integral Types in ```` Header","July 2022","|Complete|","16.0" "`P2302R4 `__","LWG","``std::ranges::contains``","July 2022","","" "`P2322R6 `__","LWG","``ranges::fold``","July 2022","","" "`P2374R4 `__","LWG","``views::cartesian_product``","July 2022","","" diff --git a/libcxx/include/__charconv/tables.h b/libcxx/include/__charconv/tables.h --- a/libcxx/include/__charconv/tables.h +++ b/libcxx/include/__charconv/tables.h @@ -27,6 +27,141 @@ /// /// In C++17 these could be inline constexpr variable, but libc++ supports /// charconv for integrals in C++11 mode. +#if _LIBCPP_STD_VER > 14 +// TODO(mordante) look at consolidating the tables for C++11/14 and C++17/20/2b +template +struct __table { + static 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'}; + + static 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', + '4', '1', '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '5', '0', '5', '1', '5', '2', '5', '3', + '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'}; + + static 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', + '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', '2', 'a', '2', 'b', '2', 'c', '2', 'd', + '2', 'e', '2', 'f', '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', + '9', '3', 'a', '3', 'b', '3', 'c', '3', 'd', '3', 'e', '3', 'f', '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', + '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '4', 'a', '4', 'b', '4', 'c', '4', 'd', '4', 'e', '4', 'f', '5', + '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', '5', 'a', '5', 'b', + '5', 'c', '5', 'd', '5', 'e', '5', 'f', '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', + '7', '6', '8', '6', '9', '6', 'a', '6', 'b', '6', 'c', '6', 'd', '6', 'e', '6', 'f', '7', '0', '7', '1', '7', '2', + '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', '7', 'a', '7', 'b', '7', 'c', '7', 'd', '7', + 'e', '7', 'f', '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', + '8', 'a', '8', 'b', '8', 'c', '8', 'd', '8', 'e', '8', 'f', '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', + '5', '9', '6', '9', '7', '9', '8', '9', '9', '9', 'a', '9', 'b', '9', 'c', '9', 'd', '9', 'e', '9', 'f', 'a', '0', + 'a', '1', 'a', '2', 'a', '3', 'a', '4', 'a', '5', 'a', '6', 'a', '7', 'a', '8', 'a', '9', 'a', 'a', 'a', 'b', 'a', + 'c', 'a', 'd', 'a', 'e', 'a', 'f', 'b', '0', 'b', '1', 'b', '2', 'b', '3', 'b', '4', 'b', '5', 'b', '6', 'b', '7', + 'b', '8', 'b', '9', 'b', 'a', 'b', 'b', 'b', 'c', 'b', 'd', 'b', 'e', 'b', 'f', 'c', '0', 'c', '1', 'c', '2', 'c', + '3', 'c', '4', 'c', '5', 'c', '6', 'c', '7', 'c', '8', 'c', '9', 'c', 'a', 'c', 'b', 'c', 'c', 'c', 'd', 'c', 'e', + 'c', 'f', 'd', '0', 'd', '1', 'd', '2', 'd', '3', 'd', '4', 'd', '5', 'd', '6', 'd', '7', 'd', '8', 'd', '9', 'd', + 'a', 'd', 'b', 'd', 'c', 'd', 'd', 'd', 'e', 'd', 'f', 'e', '0', 'e', '1', 'e', '2', 'e', '3', 'e', '4', 'e', '5', + 'e', '6', 'e', '7', 'e', '8', 'e', '9', 'e', 'a', 'e', 'b', 'e', 'c', 'e', 'd', 'e', 'e', 'e', 'f', 'f', '0', 'f', + '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'}; + + static 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)}; + + static constexpr uint64_t __pow10_64[20] = { + UINT64_C(0), + UINT64_C(10), + UINT64_C(100), + UINT64_C(1000), + UINT64_C(10000), + UINT64_C(100000), + UINT64_C(1000000), + UINT64_C(10000000), + UINT64_C(100000000), + UINT64_C(1000000000), + UINT64_C(10000000000), + UINT64_C(100000000000), + UINT64_C(1000000000000), + UINT64_C(10000000000000), + UINT64_C(100000000000000), + UINT64_C(1000000000000000), + UINT64_C(10000000000000000), + UINT64_C(100000000000000000), + UINT64_C(1000000000000000000), + UINT64_C(10000000000000000000)}; + +# ifndef _LIBCPP_HAS_NO_INT128 + // TODO FMT Reduce the number of entries in this table. + static constexpr __uint128_t __pow10_128[40] = { + UINT64_C(0), + UINT64_C(10), + UINT64_C(100), + UINT64_C(1000), + UINT64_C(10000), + UINT64_C(100000), + UINT64_C(1000000), + UINT64_C(10000000), + UINT64_C(100000000), + UINT64_C(1000000000), + UINT64_C(10000000000), + UINT64_C(100000000000), + UINT64_C(1000000000000), + UINT64_C(10000000000000), + UINT64_C(100000000000000), + UINT64_C(1000000000000000), + UINT64_C(10000000000000000), + UINT64_C(100000000000000000), + UINT64_C(1000000000000000000), + UINT64_C(10000000000000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(10), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(100), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(1000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(10000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(100000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(1000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(10000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(100000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(1000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(10000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(100000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(1000000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(10000000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(100000000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(1000000000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(10000000000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(100000000000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(1000000000000000000), + __uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(10000000000000000000), + (__uint128_t(UINT64_C(10000000000000000000)) * UINT64_C(10000000000000000000)) * 10}; + + static constexpr int __pow10_128_offset = 0; +# endif + static constexpr char __digits_base_10[200] = { + '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', '2', '0', '2', '1', '2', '2', + '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', '3', '0', '3', '1', '3', '2', '3', '3', '3', + '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', '4', '5', + '4', '6', '4', '7', '4', '8', '4', '9', '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', + '7', '5', '8', '5', '9', '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', + '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', '8', + '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', '9', '0', '9', '1', + '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'}; +}; +#else + template struct __table { static const char __base_2_lut[64]; @@ -171,6 +306,7 @@ '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'}; // clang-format on +#endif } // namespace __itoa #endif // _LIBCPP_CXX03_LANG diff --git a/libcxx/include/__charconv/to_chars_base_10.h b/libcxx/include/__charconv/to_chars_base_10.h --- a/libcxx/include/__charconv/to_chars_base_10.h +++ b/libcxx/include/__charconv/to_chars_base_10.h @@ -29,50 +29,50 @@ namespace __itoa { -_LIBCPP_HIDE_FROM_ABI inline char* __append1(char* __first, uint32_t __value) noexcept { +_LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI inline char* __append1(char* __first, uint32_t __value) noexcept { *__first = '0' + static_cast(__value); return __first + 1; } -_LIBCPP_HIDE_FROM_ABI inline char* __append2(char* __first, uint32_t __value) noexcept { +_LIBCPP_CONSTEXPR_AFTER_CXX20 _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_HIDE_FROM_ABI inline char* __append3(char* __first, uint32_t __value) noexcept { +_LIBCPP_CONSTEXPR_AFTER_CXX20 _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_AFTER_CXX20 _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_AFTER_CXX20 _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_AFTER_CXX20 _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_AFTER_CXX20 _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_AFTER_CXX20 _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_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI inline char* __append9(char* __first, uint32_t __value) noexcept { return __itoa::__append8(__itoa::__append1(__first, __value / 100000000), __value % 100000000); } template -_LIBCPP_HIDE_FROM_ABI char* __append10(char* __first, _Tp __value) noexcept { +_LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI char* __append10(char* __first, _Tp __value) noexcept { return __itoa::__append8(__itoa::__append2(__first, static_cast(__value / 100000000)), static_cast(__value % 100000000)); } -_LIBCPP_HIDE_FROM_ABI inline char* __base_10_u32(char* __first, uint32_t __value) noexcept { +_LIBCPP_CONSTEXPR_AFTER_CXX20 _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 @@ return __itoa::__append10(__first, __value); } -_LIBCPP_HIDE_FROM_ABI inline char* __base_10_u64(char* __buffer, uint64_t __value) noexcept { +_LIBCPP_CONSTEXPR_AFTER_CXX20 _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(__value)); @@ -129,12 +129,12 @@ /// \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_CONSTEXPR_AFTER_CXX20 _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_HIDE_FROM_ABI inline char* __base_10_u128(char* __buffer, __uint128_t __value) noexcept { +_LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI inline char* __base_10_u128(char* __buffer, __uint128_t __value) noexcept { _LIBCPP_ASSERT( __value > numeric_limits::max(), "The optimizations for this algorithm fail when this isn't true."); diff --git a/libcxx/include/__config b/libcxx/include/__config --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -849,6 +849,12 @@ # define _LIBCPP_CONSTEXPR_AFTER_CXX17 # endif +# if _LIBCPP_STD_VER > 20 +# define _LIBCPP_CONSTEXPR_AFTER_CXX20 constexpr +# else +# define _LIBCPP_CONSTEXPR_AFTER_CXX20 +# endif + # if __has_cpp_attribute(nodiscard) || defined(_LIBCPP_COMPILER_MSVC) # define _LIBCPP_NODISCARD [[nodiscard]] # elif defined(_LIBCPP_COMPILER_CLANG_BASED) && !defined(_LIBCPP_CXX03_LANG) diff --git a/libcxx/include/charconv b/libcxx/include/charconv --- a/libcxx/include/charconv +++ b/libcxx/include/charconv @@ -30,8 +30,8 @@ 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 @@ 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 @@ */ +#include <__algorithm/copy_n.h> #include <__assert> // all public C++ headers provide the assertion handler #include <__availability> #include <__bits> @@ -88,6 +89,7 @@ #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 // for log2f @@ -134,18 +136,18 @@ /// 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_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI int __width(_Tp __v) { auto __t = (32 - std::__libcpp_clz(static_cast(__v | 1))) * 1233 >> 12; return __t - (__v < __table<>::__pow10_32[__t]) + 1; } - static _LIBCPP_HIDE_FROM_ABI char* __convert(char* __p, _Tp __v) + static _LIBCPP_CONSTEXPR_AFTER_CXX20 _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_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI decltype(__table<>::__pow10_32)& __pow() { return __table<>::__pow10_32; } }; template @@ -161,14 +163,14 @@ /// 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_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI int __width(_Tp __v) { auto __t = (64 - std::__libcpp_clz(static_cast(__v | 1))) * 1233 >> 12; return __t - (__v < __table<>::__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_AFTER_CXX20 _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_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI decltype(__table<>::__pow10_64)& __pow() { return __table<>::__pow10_64; } }; @@ -186,7 +188,7 @@ /// 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_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI int __width(_Tp __v) { _LIBCPP_ASSERT(__v > numeric_limits::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(__v >> 64))) * 1233 >> 12; @@ -195,16 +197,16 @@ return __t - (__v < __table<>::__pow10_128[__t - __table<>::__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_AFTER_CXX20 _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_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI decltype(__table<>::__pow10_128)& __pow() { return __table<>::__pow10_128; } }; #endif template -inline _LIBCPP_HIDE_FROM_ABI bool +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI bool __mul_overflowed(unsigned char __a, _Tp __b, unsigned char& __r) { auto __c = __a * __b; @@ -213,7 +215,7 @@ } template -inline _LIBCPP_HIDE_FROM_ABI bool +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI bool __mul_overflowed(unsigned short __a, _Tp __b, unsigned short& __r) { auto __c = __a * __b; @@ -222,7 +224,7 @@ } template -inline _LIBCPP_HIDE_FROM_ABI bool +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI bool __mul_overflowed(_Tp __a, _Tp __b, _Tp& __r) { static_assert(is_unsigned<_Tp>::value, ""); @@ -237,7 +239,7 @@ template inline _LIBCPP_HIDE_FROM_ABI bool -__mul_overflowed(_Tp __a, _Up __b, _Tp& __r) +_LIBCPP_CONSTEXPR_AFTER_CXX20 __mul_overflowed(_Tp __a, _Up __b, _Tp& __r) { return __mul_overflowed(__a, static_cast<_Tp>(__b), __r); } @@ -250,7 +252,7 @@ using typename __traits_base<_Tp>::type; // precondition: at least one non-zero character available - static _LIBCPP_HIDE_FROM_ABI char const* + static _LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI char const* __read(char const* __p, char const* __ep, type& __a, type& __b) { type __cprod[digits]; @@ -271,7 +273,7 @@ } template - static _LIBCPP_HIDE_FROM_ABI _Up + static _LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI _Up __inner_product(_It1 __first1, _It1 __last1, _It2 __first2, _Up __init) { for (; __first1 < __last1; ++__first1, ++__first2) @@ -283,7 +285,7 @@ } // namespace __itoa template -inline _LIBCPP_HIDE_FROM_ABI _Tp +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI _Tp __complement(_Tp __x) { static_assert(is_unsigned<_Tp>::value, "cast to unsigned first"); @@ -291,7 +293,7 @@ } template -inline _LIBCPP_HIDE_FROM_ABI to_chars_result +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI to_chars_result __to_chars_itoa(char* __first, char* __last, _Tp __value, true_type) { auto __x = __to_unsigned_like(__value); @@ -305,7 +307,7 @@ } template -inline _LIBCPP_HIDE_FROM_ABI to_chars_result +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI to_chars_result __to_chars_itoa(char* __first, char* __last, _Tp __value, false_type) { using __tx = __itoa::__traits<_Tp>; @@ -319,7 +321,7 @@ # ifndef _LIBCPP_HAS_NO_INT128 template <> -inline _LIBCPP_HIDE_FROM_ABI to_chars_result +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _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 @@ -340,7 +342,7 @@ #endif template -inline _LIBCPP_HIDE_FROM_ABI to_chars_result +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI to_chars_result __to_chars_integral(char* __first, char* __last, _Tp __value, int __base, true_type) { @@ -370,7 +372,7 @@ } template - _LIBCPP_HIDE_FROM_ABI static to_chars_result __to_chars(char* __first, char* __last, _Tp __value) { + _LIBCPP_CONSTEXPR_AFTER_CXX20 _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) @@ -383,7 +385,7 @@ unsigned __c = __value % __divisor; __value /= __divisor; __p -= 4; - std::memcpy(__p, &__table<>::__base_2_lut[4 * __c], 4); + std::copy_n(std::addressof(__table<>::__base_2_lut[4 * __c]), 4, __p); } do { unsigned __c = __value % 2; @@ -405,7 +407,7 @@ } template - _LIBCPP_HIDE_FROM_ABI static to_chars_result __to_chars(char* __first, char* __last, _Tp __value) { + _LIBCPP_CONSTEXPR_AFTER_CXX20 _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) @@ -418,7 +420,7 @@ unsigned __c = __value % __divisor; __value /= __divisor; __p -= 2; - std::memcpy(__p, &__table<>::__base_8_lut[2 * __c], 2); + std::copy_n(std::addressof(__table<>::__base_8_lut[2 * __c]), 2, __p); } do { unsigned __c = __value % 8; @@ -441,7 +443,7 @@ } template - _LIBCPP_HIDE_FROM_ABI static to_chars_result __to_chars(char* __first, char* __last, _Tp __value) { + _LIBCPP_CONSTEXPR_AFTER_CXX20 _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) @@ -454,7 +456,7 @@ unsigned __c = __value % __divisor; __value /= __divisor; __p -= 2; - std::memcpy(__p, &__table<>::__base_16_lut[2 * __c], 2); + std::copy_n(std::addressof(__table<>::__base_16_lut[2 * __c]), 2, __p); } if (__first != __last) do { @@ -470,34 +472,34 @@ template = sizeof(unsigned)), int>::type = 0> -_LIBCPP_HIDE_FROM_ABI int +_LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI int __to_chars_integral_width(_Tp __value) { return __itoa::__integral<_Base>::__width(__value); } template ::type = 0> -_LIBCPP_HIDE_FROM_ABI int +_LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI int __to_chars_integral_width(_Tp __value) { return std::__to_chars_integral_width<_Base>(static_cast(__value)); } template = sizeof(unsigned)), int>::type = 0> -_LIBCPP_HIDE_FROM_ABI to_chars_result +_LIBCPP_CONSTEXPR_AFTER_CXX20 _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 ::type = 0> -_LIBCPP_HIDE_FROM_ABI to_chars_result +_LIBCPP_CONSTEXPR_AFTER_CXX20 _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(__value)); } template -_LIBCPP_HIDE_FROM_ABI int +_LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI int __to_chars_integral_width(_Tp __value, unsigned __base) { _LIBCPP_ASSERT(__value >= 0, "The function requires a non-negative value."); @@ -524,7 +526,7 @@ } template -inline _LIBCPP_HIDE_FROM_ABI to_chars_result +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI to_chars_result __to_chars_integral(char* __first, char* __last, _Tp __value, int __base, false_type) { @@ -556,7 +558,7 @@ } template ::value, int>::type = 0> -inline _LIBCPP_HIDE_FROM_ABI to_chars_result +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _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>; @@ -565,7 +567,7 @@ } template ::value, int>::type = 0> -inline _LIBCPP_HIDE_FROM_ABI to_chars_result +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _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]"); @@ -575,7 +577,7 @@ } template -inline _LIBCPP_HIDE_FROM_ABI from_chars_result +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI from_chars_result __sign_combinator(_It __first, _It __last, _Tp& __value, _Fn __f, _Ts... __args) { using __tl = numeric_limits<_Tp>; @@ -598,7 +600,7 @@ 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; } } @@ -615,7 +617,7 @@ } template -inline _LIBCPP_HIDE_FROM_ABI bool +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI bool __in_pattern(_Tp __c) { return '0' <= __c && __c <= '9'; @@ -626,11 +628,11 @@ bool __ok; int __val; - explicit _LIBCPP_HIDE_FROM_ABI operator bool() const { return __ok; } + explicit _LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI operator bool() const { return __ok; } }; template -inline _LIBCPP_HIDE_FROM_ABI __in_pattern_result +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI __in_pattern_result __in_pattern(_Tp __c, int __base) { if (__base <= 10) @@ -644,7 +646,7 @@ } template -inline _LIBCPP_HIDE_FROM_ABI from_chars_result +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI from_chars_result __subject_seq_combinator(_It __first, _It __last, _Tp& __value, _Fn __f, _Ts... __args) { @@ -681,7 +683,7 @@ } template ::value, int>::type = 0> -inline _LIBCPP_HIDE_FROM_ABI from_chars_result +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI from_chars_result __from_chars_atoi(const char* __first, const char* __last, _Tp& __value) { using __tx = __itoa::__traits<_Tp>; @@ -707,15 +709,36 @@ } template ::value, int>::type = 0> -inline _LIBCPP_HIDE_FROM_ABI from_chars_result +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _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>); } + +#if _LIBCPP_STD_VER > 14 +/* +// Digraphs to avoid the header cycle detection script. +%:include +%:include +%:include + +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}; +# endif + template ::value, int>::type = 0> -inline _LIBCPP_HIDE_FROM_ABI from_chars_result +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI from_chars_result __from_chars_integral(const char* __first, const char* __last, _Tp& __value, int __base) { @@ -727,7 +750,11 @@ [](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)); +#if _LIBCPP_STD_VER > 14 + auto __digits = __tl::digits / __from_chars_log2f_lut[__b - 2]; +#else + auto __digits = __tl::digits / log2f(float(__b)); +#endif _Tp __x = __in_pattern(*__p++, __b).__val, __y = 0; for (int __i = 1; __p != __lastp; ++__i, ++__p) @@ -762,7 +789,7 @@ } template ::value, int>::type = 0> -inline _LIBCPP_HIDE_FROM_ABI from_chars_result +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _LIBCPP_HIDE_FROM_ABI from_chars_result __from_chars_integral(const char* __first, const char* __last, _Tp& __value, int __base) { @@ -772,14 +799,14 @@ } template ::value, int>::type = 0> -inline _LIBCPP_HIDE_FROM_ABI from_chars_result +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _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 ::value, int>::type = 0> -inline _LIBCPP_HIDE_FROM_ABI from_chars_result +inline _LIBCPP_CONSTEXPR_AFTER_CXX20 _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]"); diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -56,6 +56,7 @@ __cpp_lib_complex_udls 201309L __cpp_lib_concepts 202002L __cpp_lib_constexpr_algorithms 201806L +__cpp_lib_constexpr_charconv 202207L __cpp_lib_constexpr_cmath 202202L __cpp_lib_constexpr_complex 201711L __cpp_lib_constexpr_dynamic_alloc 201907L @@ -380,6 +381,7 @@ // # define __cpp_lib_associative_heterogeneous_erasure 202110L // # define __cpp_lib_bind_back 202202L # define __cpp_lib_byteswap 202110L +# define __cpp_lib_constexpr_charconv 202207L // # define __cpp_lib_constexpr_cmath 202202L // # define __cpp_lib_constexpr_typeinfo 202106L // # define __cpp_lib_invoke_r 202106L diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/charconv.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/charconv.version.compile.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/charconv.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/charconv.version.compile.pass.cpp @@ -15,8 +15,9 @@ // Test the feature test macros defined by -/* 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 @@ -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" diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -52,6 +52,7 @@ __cpp_lib_complex_udls 201309L [C++14] __cpp_lib_concepts 202002L [C++20] __cpp_lib_constexpr_algorithms 201806L [C++20] + __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] @@ -324,6 +325,10 @@ # error "__cpp_lib_constexpr_algorithms should not be defined before c++20" # 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 @@ -952,6 +957,10 @@ # error "__cpp_lib_constexpr_algorithms should not be defined before c++20" # 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 @@ -1676,6 +1685,10 @@ # error "__cpp_lib_constexpr_algorithms should not be defined before c++20" # 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 @@ -2646,6 +2659,10 @@ # error "__cpp_lib_constexpr_algorithms should have the value 201806L in c++20" # 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 @@ -3865,6 +3882,13 @@ # error "__cpp_lib_constexpr_algorithms should have the value 201806L 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" diff --git a/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.pass.cpp b/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.pass.cpp --- a/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.pass.cpp +++ b/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.pass.cpp @@ -12,8 +12,8 @@ // -// 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 #include "test_macros.h" @@ -22,7 +22,7 @@ template struct test_basics { - void operator()() + TEST_CONSTEXPR_CXX23 void operator()() { std::from_chars_result r; T x; @@ -86,7 +86,7 @@ template struct test_signed { - void operator()() + TEST_CONSTEXPR_CXX23 void operator()() { std::from_chars_result r; T x = 42; @@ -137,10 +137,20 @@ } }; -int main(int, char**) +TEST_CONSTEXPR_CXX23 bool test() { run(integrals); run(all_signed); + return true; +} + +int main(int, char**) +{ + test(); +#if TEST_STD_VER > 20 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.roundtrip.pass.cpp b/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.roundtrip.pass.cpp --- a/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.roundtrip.pass.cpp +++ b/libcxx/test/std/utilities/charconv/charconv.from.chars/integral.roundtrip.pass.cpp @@ -12,8 +12,8 @@ // -// 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 #include "test_macros.h" @@ -24,7 +24,7 @@ { using roundtrip_test_base::test; - void operator()() + TEST_CONSTEXPR_CXX23 void operator()() { test(0); test(42); @@ -54,7 +54,7 @@ { using roundtrip_test_base::test; - void operator()() + TEST_CONSTEXPR_CXX23 void operator()() { test(-1); test(-12); @@ -75,10 +75,20 @@ } }; -int main(int, char**) +TEST_CONSTEXPR_CXX23 bool test() { run(integrals); run(all_signed); + return true; +} + +int main(int, char**) +{ + test(); +#if TEST_STD_VER > 20 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/std/utilities/charconv/charconv.to.chars/integral.pass.cpp b/libcxx/test/std/utilities/charconv/charconv.to.chars/integral.pass.cpp --- a/libcxx/test/std/utilities/charconv/charconv.to.chars/integral.pass.cpp +++ b/libcxx/test/std/utilities/charconv/charconv.to.chars/integral.pass.cpp @@ -12,34 +12,34 @@ // -// 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 #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); @@ -52,7 +52,7 @@ using to_chars_test_base::test; using to_chars_test_base::test_value; - void operator()() + TEST_CONSTEXPR_CXX23 void operator()() { test(0, "0"); test(42, "42"); @@ -174,7 +174,7 @@ using to_chars_test_base::test; using to_chars_test_base::test_value; - void operator()() + TEST_CONSTEXPR_CXX23 void operator()() { test(-1, "-1"); test(-12, "-12"); @@ -288,10 +288,20 @@ } }; -int main(int, char**) +TEST_CONSTEXPR_CXX23 bool test() { run(integrals); run(all_signed); + return true; +} + +int main(int, char**) +{ + test(); +#if TEST_STD_VER > 20 + static_assert(test()); +#endif + return 0; } diff --git a/libcxx/test/support/charconv_test_helpers.h b/libcxx/test/support/charconv_test_helpers.h --- a/libcxx/test/support/charconv_test_helpers.h +++ b/libcxx/test/support/charconv_test_helpers.h @@ -78,7 +78,7 @@ struct to_chars_test_base { template - 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; @@ -96,22 +96,23 @@ r = 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(__builtin_memcmp(buf, expect, len) == 0); } template - 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)); + // 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(1)); r = 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(i + 1)); + assert(static_cast(buf[i]) == i + 1); *r.ptr = '\0'; #ifndef TEST_HAS_NO_INT128 @@ -132,36 +133,47 @@ } 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(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(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 +181,18 @@ 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 +200,7 @@ 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())) { return fromchars128_impl(p, ep, base, std::is_signed()); @@ -193,7 +208,7 @@ #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())) { return fromchars_impl(p, ep, base, std::is_signed()); @@ -206,7 +221,7 @@ struct roundtrip_test_base { template - void test(T v, Ts... args) + TEST_CONSTEXPR_CXX23 void test(T v, Ts... args) { using std::from_chars; using std::to_chars; @@ -303,7 +318,7 @@ auto integrals = concat(all_signed, all_unsigned); template