aboutsummaryrefslogtreecommitdiff
path: root/libcxx/include/charconv
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2022-07-14 18:50:02 +0000
committerDimitry Andric <dim@FreeBSD.org>2022-07-14 18:50:02 +0000
commit1f917f69ff07f09b6dbb670971f57f8efe718b84 (patch)
tree99293cbc1411737cd995dac10a99b2c40ef0944c /libcxx/include/charconv
parent145449b1e420787bb99721a429341fa6be3adfb6 (diff)
downloadsrc-1f917f69ff07f09b6dbb670971f57f8efe718b84.tar.gz
src-1f917f69ff07f09b6dbb670971f57f8efe718b84.zip
Vendor import of llvm-project main llvmorg-15-init-16436-g18a6ab5b8d1f.vendor/llvm-project/llvmorg-15-init-16436-g18a6ab5b8d1f
Diffstat (limited to 'libcxx/include/charconv')
-rw-r--r--libcxx/include/charconv135
1 files changed, 100 insertions, 35 deletions
diff --git a/libcxx/include/charconv b/libcxx/include/charconv
index 6a63e5fe9057..9f474ae711f3 100644
--- a/libcxx/include/charconv
+++ b/libcxx/include/charconv
@@ -117,32 +117,22 @@ from_chars_result from_chars(const char*, const char*, bool, int = 10) = delete;
namespace __itoa
{
-
template <typename _Tp, typename = void>
-struct _LIBCPP_HIDDEN __traits_base
-{
- using type = uint64_t;
-
- static _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;
- }
-
- static _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; }
-};
+struct _LIBCPP_HIDDEN __traits_base;
template <typename _Tp>
-struct _LIBCPP_HIDDEN
- __traits_base<_Tp, decltype(void(uint32_t{declval<_Tp>()}))>
+struct _LIBCPP_HIDDEN __traits_base<_Tp, __enable_if_t<sizeof(_Tp) <= sizeof(uint32_t)>>
{
using type = uint32_t;
+ /// The width estimation using a log10 algorithm.
+ ///
+ /// The algorithm is based on
+ /// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
+ /// Instead of using IntegerLogBase2 it uses __libcpp_clz. Since that
+ /// 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)
{
auto __t = (32 - std::__libcpp_clz(static_cast<type>(__v | 1))) * 1233 >> 12;
@@ -158,6 +148,61 @@ struct _LIBCPP_HIDDEN
};
template <typename _Tp>
+struct _LIBCPP_HIDDEN
+ __traits_base<_Tp, __enable_if_t<sizeof(_Tp) == sizeof(uint64_t)>> {
+ using type = uint64_t;
+
+ /// The width estimation using a log10 algorithm.
+ ///
+ /// The algorithm is based on
+ /// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
+ /// Instead of using IntegerLogBase2 it uses __libcpp_clz. Since that
+ /// 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) {
+ auto __t = (64 - std::__libcpp_clz(static_cast<type>(__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_HIDE_FROM_ABI decltype(__table<>::__pow10_64)& __pow() { return __table<>::__pow10_64; }
+};
+
+
+# ifndef _LIBCPP_HAS_NO_INT128
+template <typename _Tp>
+struct _LIBCPP_HIDDEN
+ __traits_base<_Tp, __enable_if_t<sizeof(_Tp) == sizeof(__uint128_t)> > {
+ using type = __uint128_t;
+
+ /// The width estimation using a log10 algorithm.
+ ///
+ /// The algorithm is based on
+ /// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
+ /// Instead of using IntegerLogBase2 it uses __libcpp_clz. Since that
+ /// 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) {
+ _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");
+ // __t is adjusted since the lookup table misses the lower entries.
+ 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); }
+
+ // 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; }
+};
+#endif
+
+template <typename _Tp>
inline _LIBCPP_HIDE_FROM_ABI bool
__mul_overflowed(unsigned char __a, _Tp __b, unsigned char& __r)
{
@@ -271,6 +316,28 @@ __to_chars_itoa(char* __first, char* __last, _Tp __value, false_type)
return {__last, errc::value_too_large};
}
+# ifndef _LIBCPP_HAS_NO_INT128
+template <>
+inline _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
+ // the number of expensive calculations on 128-bit values.
+ //
+ // NOTE the 128-bit code path requires this optimization.
+ if(__value <= numeric_limits<uint64_t>::max())
+ return __to_chars_itoa(__first, __last, static_cast<uint64_t>(__value), false_type());
+
+ using __tx = __itoa::__traits<__uint128_t>;
+ auto __diff = __last - __first;
+
+ if (__tx::digits <= __diff || __tx::__width(__value) <= __diff)
+ return {__tx::__convert(__first, __value), errc(0)};
+ else
+ return {__last, errc::value_too_large};
+}
+#endif
+
template <typename _Tp>
inline _LIBCPP_HIDE_FROM_ABI to_chars_result
__to_chars_integral(char* __first, char* __last, _Tp __value, int __base,
@@ -493,7 +560,6 @@ to_chars(char* __first, char* __last, _Tp __value)
{
using _Type = __make_32_64_or_128_bit_t<_Tp>;
static_assert(!is_same<_Type, void>::value, "unsupported integral type used in to_chars");
- static_assert(sizeof(_Tp) <= sizeof(int64_t), "128-bit integral support isn't available yet in to_chars");
return std::__to_chars_itoa(__first, __last, static_cast<_Type>(__value), is_signed<_Tp>());
}
@@ -504,7 +570,6 @@ to_chars(char* __first, char* __last, _Tp __value, int __base)
_LIBCPP_ASSERT(2 <= __base && __base <= 36, "base not in [2, 36]");
using _Type = __make_32_64_or_128_bit_t<_Tp>;
- static_assert(sizeof(_Tp) <= sizeof(int64_t), "128-bit integral support isn't available yet in to_chars");
return std::__to_chars_integral(__first, __last, static_cast<_Type>(__value), __base, is_signed<_Tp>());
}
@@ -623,11 +688,11 @@ __from_chars_atoi(const char* __first, const char* __last, _Tp& __value)
return __subject_seq_combinator(
__first, __last, __value,
- [](const char* _First, const char* _Last,
+ [](const char* __f, const char* __l,
_Tp& __val) -> from_chars_result {
__output_type __a, __b;
- auto __p = __tx::__read(_First, _Last, __a, __b);
- if (__p == _Last || !__in_pattern(*__p))
+ auto __p = __tx::__read(__f, __l, __a, __b);
+ if (__p == __l || !__in_pattern(*__p))
{
__output_type __m = numeric_limits<_Tp>::max();
if (__m >= __a && __m - __a >= __b)
@@ -659,22 +724,22 @@ __from_chars_integral(const char* __first, const char* __last, _Tp& __value,
return __subject_seq_combinator(
__first, __last, __value,
[](const char* __p, const char* __lastp, _Tp& __val,
- int _Base) -> from_chars_result {
+ int __b) -> from_chars_result {
using __tl = numeric_limits<_Tp>;
- auto __digits = __tl::digits / log2f(float(_Base));
- _Tp __a = __in_pattern(*__p++, _Base).__val, __b = 0;
+ auto __digits = __tl::digits / log2f(float(__b));
+ _Tp __x = __in_pattern(*__p++, __b).__val, __y = 0;
for (int __i = 1; __p != __lastp; ++__i, ++__p)
{
- if (auto __c = __in_pattern(*__p, _Base))
+ if (auto __c = __in_pattern(*__p, __b))
{
if (__i < __digits - 1)
- __a = __a * _Base + __c.__val;
+ __x = __x * __b + __c.__val;
else
{
- if (!__itoa::__mul_overflowed(__a, _Base, __a))
+ if (!__itoa::__mul_overflowed(__x, __b, __x))
++__p;
- __b = __c.__val;
+ __y = __c.__val;
break;
}
}
@@ -682,11 +747,11 @@ __from_chars_integral(const char* __first, const char* __last, _Tp& __value,
break;
}
- if (__p == __lastp || !__in_pattern(*__p, _Base))
+ if (__p == __lastp || !__in_pattern(*__p, __b))
{
- if (__tl::max() - __a >= __b)
+ if (__tl::max() - __x >= __y)
{
- __val = __a + __b;
+ __val = __x + __y;
return {__p, {}};
}
}