Skip to content

Commit

Permalink
[libc++] Implements constexpr <charconv>.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mordante committed Oct 12, 2022
1 parent 261b5ab commit a1e13a8
Show file tree
Hide file tree
Showing 15 changed files with 264 additions and 168 deletions.
2 changes: 2 additions & 0 deletions libcxx/docs/FeatureTestMacroTable.rst
Expand Up @@ -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``
Expand Down
2 changes: 2 additions & 0 deletions libcxx/docs/ReleaseNotes.rst
Expand Up @@ -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
-----------------------------
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx2bPapers.csv
Expand Up @@ -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","",""
Expand Down
42 changes: 8 additions & 34 deletions libcxx/include/__charconv/tables.h
Expand Up @@ -23,43 +23,20 @@ _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',
'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'};

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',
Expand All @@ -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),
Expand All @@ -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),
Expand Down Expand Up @@ -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',
Expand Down
34 changes: 17 additions & 17 deletions libcxx/include/__charconv/to_chars_base_10.h
Expand Up @@ -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) {
Expand Down Expand Up @@ -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));

Expand All @@ -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.");

Expand Down

0 comments on commit a1e13a8

Please sign in to comment.