forked from OSchip/llvm-project
[libc++][format] Implements 128-bit support.
With to_chars supporting 128-bit it's possible to support the full 128-bit range in format. This only removes the previous restrictions and updates the tests to validate proper support. Depends on D128929. Reviewed By: #libc, ldionne Differential Revision: https://reviews.llvm.org/D129007
This commit is contained in:
parent
d955185b94
commit
0857a02ef0
|
@ -13,23 +13,18 @@
|
|||
#include <__availability>
|
||||
#include <__concepts/arithmetic.h>
|
||||
#include <__config>
|
||||
#include <__format/format_error.h> // TODO FMT Remove after adding 128-bit support
|
||||
#include <__format/format_fwd.h>
|
||||
#include <__format/format_parse_context.h>
|
||||
#include <__format/formatter.h>
|
||||
#include <__format/formatter_integral.h>
|
||||
#include <__format/formatter_output.h>
|
||||
#include <__format/parser_std_format_spec.h>
|
||||
#include <limits> // TODO FMT Remove after adding 128-bit support
|
||||
#include <type_traits>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_PUSH_MACROS // TODO FMT Remove after adding 128-bit support
|
||||
#include <__undef_macros>
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER > 17
|
||||
|
@ -79,18 +74,7 @@ struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<long long, _Ch
|
|||
# ifndef _LIBCPP_HAS_NO_INT128
|
||||
template <__formatter::__char_type _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<__int128_t, _CharT>
|
||||
: public __formatter_integer<_CharT> {
|
||||
using _Base = __formatter_integer<_CharT>;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI auto format(__int128_t __value, auto& __ctx) const -> decltype(__ctx.out()) {
|
||||
// TODO FMT Implement full 128 bit support.
|
||||
using _To = long long;
|
||||
if (__value < numeric_limits<_To>::min() || __value > numeric_limits<_To>::max())
|
||||
std::__throw_format_error("128-bit value is outside of implemented range");
|
||||
|
||||
return _Base::format(static_cast<_To>(__value), __ctx);
|
||||
}
|
||||
};
|
||||
: public __formatter_integer<_CharT> {};
|
||||
# endif
|
||||
|
||||
// Unsigned integral types.
|
||||
|
@ -112,24 +96,11 @@ struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<unsigned long
|
|||
# ifndef _LIBCPP_HAS_NO_INT128
|
||||
template <__formatter::__char_type _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<__uint128_t, _CharT>
|
||||
: public __formatter_integer<_CharT> {
|
||||
using _Base = __formatter_integer<_CharT>;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI auto format(__uint128_t __value, auto& __ctx) const -> decltype(__ctx.out()) {
|
||||
// TODO FMT Implement full 128 bit support.
|
||||
using _To = unsigned long long;
|
||||
if (__value < numeric_limits<_To>::min() || __value > numeric_limits<_To>::max())
|
||||
std::__throw_format_error("128-bit value is outside of implemented range");
|
||||
|
||||
return _Base::format(static_cast<_To>(__value), __ctx);
|
||||
}
|
||||
};
|
||||
: public __formatter_integer<_CharT> {};
|
||||
# endif
|
||||
|
||||
#endif //_LIBCPP_STD_VER > 17
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
_LIBCPP_POP_MACROS
|
||||
|
||||
#endif // _LIBCPP___FORMAT_FORMATTER_INTEGER_H
|
||||
|
|
|
@ -86,18 +86,17 @@ void test_signed_integral_type() {
|
|||
test_termination_condition(STR("2147483647"), STR("}"), A(2147483647));
|
||||
}
|
||||
if (sizeof(A) > 4) {
|
||||
// -9223372036854775808 can't be used directly, it gives the following
|
||||
// diagnostic:
|
||||
// integer literal is too large to be represented in a signed integer type,
|
||||
// interpreting as unsigned [-Werror,-Wimplicitly-unsigned-literal]
|
||||
test_termination_condition(STR("-9223372036854775808"), STR("}"),
|
||||
A(-9223372036854775807 - 1));
|
||||
test_termination_condition(STR("9223372036854775807"), STR("}"),
|
||||
A(9223372036854775807));
|
||||
test_termination_condition(STR("-9223372036854775808"), STR("}"), A(std::numeric_limits<int64_t>::min()));
|
||||
test_termination_condition(STR("9223372036854775807"), STR("}"), A(std::numeric_limits<int64_t>::max()));
|
||||
}
|
||||
|
||||
// TODO FMT Implement the __int128_t minimum and maximum once the formatter
|
||||
// can handle these values.
|
||||
#ifndef TEST_HAS_NO_INT128
|
||||
if (sizeof(A) > 8) {
|
||||
test_termination_condition(
|
||||
STR("-170141183460469231731687303715884105728"), STR("}"), A(std::numeric_limits<__int128_t>::min()));
|
||||
test_termination_condition(
|
||||
STR("170141183460469231731687303715884105727"), STR("}"), A(std::numeric_limits<__int128_t>::max()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
|
|
|
@ -83,9 +83,11 @@ void test_unsigned_integral_type() {
|
|||
if (sizeof(A) > 4)
|
||||
test_termination_condition(STR("8446744073709551615"), STR("}"),
|
||||
A(8446744073709551615));
|
||||
|
||||
// TODO FMT Implement the __uint128_t maximum once the formatter can handle
|
||||
// these values.
|
||||
#ifndef TEST_HAS_NO_INT128
|
||||
if (sizeof(A) > 8)
|
||||
test_termination_condition(
|
||||
STR("340282366920938463463374607431768211455"), STR("}"), A(std::numeric_limits<__uint128_t>::max()));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
|
|
|
@ -702,19 +702,16 @@ void format_test_integer_as_char(TestFunction check, ExceptionTest check_excepti
|
|||
check_exception("The format-spec type has a type not supported for an integer argument", fmt, I(42));
|
||||
|
||||
// *** Validate range ***
|
||||
// TODO FMT Update test after adding 128-bit support.
|
||||
if constexpr (sizeof(I) <= sizeof(long long)) {
|
||||
// The code has some duplications to keep the if statement readable.
|
||||
if constexpr (std::signed_integral<CharT>) {
|
||||
if constexpr (std::signed_integral<I> && sizeof(I) > sizeof(CharT)) {
|
||||
check_exception("Integral value outside the range of the char type", SV("{:c}"), std::numeric_limits<I>::min());
|
||||
check_exception("Integral value outside the range of the char type", SV("{:c}"), std::numeric_limits<I>::max());
|
||||
} else if constexpr (std::unsigned_integral<I> && sizeof(I) >= sizeof(CharT)) {
|
||||
check_exception("Integral value outside the range of the char type", SV("{:c}"), std::numeric_limits<I>::max());
|
||||
}
|
||||
} else if constexpr (sizeof(I) > sizeof(CharT)) {
|
||||
// The code has some duplications to keep the if statement readable.
|
||||
if constexpr (std::signed_integral<CharT>) {
|
||||
if constexpr (std::signed_integral<I> && sizeof(I) > sizeof(CharT)) {
|
||||
check_exception("Integral value outside the range of the char type", SV("{:c}"), std::numeric_limits<I>::min());
|
||||
check_exception("Integral value outside the range of the char type", SV("{:c}"), std::numeric_limits<I>::max());
|
||||
} else if constexpr (std::unsigned_integral<I> && sizeof(I) >= sizeof(CharT)) {
|
||||
check_exception("Integral value outside the range of the char type", SV("{:c}"), std::numeric_limits<I>::max());
|
||||
}
|
||||
} else if constexpr (sizeof(I) > sizeof(CharT)) {
|
||||
check_exception("Integral value outside the range of the char type", SV("{:c}"), std::numeric_limits<I>::max());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -756,6 +753,18 @@ void format_test_signed_integer(TestFunction check, ExceptionTest check_exceptio
|
|||
check.template operator()<"{:#}">(SV("-9223372036854775808"), std::numeric_limits<int64_t>::min());
|
||||
check.template operator()<"{:#x}">(SV("-0x8000000000000000"), std::numeric_limits<int64_t>::min());
|
||||
|
||||
#ifndef TEST_HAS_NO_INT128
|
||||
check.template operator()<"{:#b}">(
|
||||
SV("-0b1000000000000000000000000000000000000000000000000000000000000000"
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
std::numeric_limits<__int128_t>::min());
|
||||
check.template
|
||||
operator()<"{:#o}">(SV("-02000000000000000000000000000000000000000000"), std::numeric_limits<__int128_t>::min());
|
||||
check.template
|
||||
operator()<"{:#}">(SV("-170141183460469231731687303715884105728"), std::numeric_limits<__int128_t>::min());
|
||||
check.template operator()<"{:#x}">(SV("-0x80000000000000000000000000000000"), std::numeric_limits<__int128_t>::min());
|
||||
#endif
|
||||
|
||||
check.template operator()<"{:#b}">(SV("0b1111111"), std::numeric_limits<int8_t>::max());
|
||||
check.template operator()<"{:#o}">(SV("0177"), std::numeric_limits<int8_t>::max());
|
||||
check.template operator()<"{:#}">(SV("127"), std::numeric_limits<int8_t>::max());
|
||||
|
@ -777,7 +786,17 @@ void format_test_signed_integer(TestFunction check, ExceptionTest check_exceptio
|
|||
check.template operator()<"{:#}">(SV("9223372036854775807"), std::numeric_limits<int64_t>::max());
|
||||
check.template operator()<"{:#x}">(SV("0x7fffffffffffffff"), std::numeric_limits<int64_t>::max());
|
||||
|
||||
// TODO FMT Add __int128_t test after implementing full range.
|
||||
#ifndef TEST_HAS_NO_INT128
|
||||
check.template operator()<"{:#b}">(
|
||||
SV("0b111111111111111111111111111111111111111111111111111111111111111"
|
||||
"1111111111111111111111111111111111111111111111111111111111111111"),
|
||||
std::numeric_limits<__int128_t>::max());
|
||||
check.template
|
||||
operator()<"{:#o}">(SV("01777777777777777777777777777777777777777777"), std::numeric_limits<__int128_t>::max());
|
||||
check.template
|
||||
operator()<"{:#}">(SV("170141183460469231731687303715884105727"), std::numeric_limits<__int128_t>::max());
|
||||
check.template operator()<"{:#x}">(SV("0x7fffffffffffffffffffffffffffffff"), std::numeric_limits<__int128_t>::max());
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class CharT, class TestFunction, class ExceptionTest>
|
||||
|
@ -812,7 +831,17 @@ void format_test_unsigned_integer(TestFunction check, ExceptionTest check_except
|
|||
check.template operator()<"{:#}">(SV("18446744073709551615"), std::numeric_limits<uint64_t>::max());
|
||||
check.template operator()<"{:#x}">(SV("0xffffffffffffffff"), std::numeric_limits<uint64_t>::max());
|
||||
|
||||
// TODO FMT Add __uint128_t test after implementing full range.
|
||||
#ifndef TEST_HAS_NO_INT128
|
||||
check.template operator()<"{:#b}">(
|
||||
SV("0b1111111111111111111111111111111111111111111111111111111111111111"
|
||||
"1111111111111111111111111111111111111111111111111111111111111111"),
|
||||
std::numeric_limits<__uint128_t>::max());
|
||||
check.template
|
||||
operator()<"{:#o}">(SV("03777777777777777777777777777777777777777777"), std::numeric_limits<__uint128_t>::max());
|
||||
check.template
|
||||
operator()<"{:#}">(SV("340282366920938463463374607431768211455"), std::numeric_limits<__uint128_t>::max());
|
||||
check.template operator()<"{:#x}">(SV("0xffffffffffffffffffffffffffffffff"), std::numeric_limits<__uint128_t>::max());
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class CharT, class TestFunction, class ExceptionTest>
|
||||
|
@ -2588,21 +2617,6 @@ void format_tests(TestFunction check, ExceptionTest check_exception) {
|
|||
check.template operator()<"hello {}">(SV("hello 42"), static_cast<long long>(42));
|
||||
#ifndef TEST_HAS_NO_INT128
|
||||
check.template operator()<"hello {}">(SV("hello 42"), static_cast<__int128_t>(42));
|
||||
{
|
||||
// Note 128-bit support is only partly implemented test the range
|
||||
// conditions here.
|
||||
static constexpr auto fmt = string_literal("{}");
|
||||
std::basic_string<CharT> min = std::format(fmt.template sv<CharT>(), std::numeric_limits<long long>::min());
|
||||
check.template operator()<"{}">(std::basic_string_view<CharT>(min),
|
||||
static_cast<__int128_t>(std::numeric_limits<long long>::min()));
|
||||
std::basic_string<CharT> max = std::format(fmt.template sv<CharT>(), std::numeric_limits<long long>::max());
|
||||
check.template operator()<"{}">(std::basic_string_view<CharT>(max),
|
||||
static_cast<__int128_t>(std::numeric_limits<long long>::max()));
|
||||
check_exception("128-bit value is outside of implemented range", SV("{}"),
|
||||
static_cast<__int128_t>(std::numeric_limits<long long>::min()) - 1);
|
||||
check_exception("128-bit value is outside of implemented range", SV("{}"),
|
||||
static_cast<__int128_t>(std::numeric_limits<long long>::max()) + 1);
|
||||
}
|
||||
#endif
|
||||
format_test_signed_integer<CharT>(check, check_exception);
|
||||
|
||||
|
@ -2614,16 +2628,6 @@ void format_tests(TestFunction check, ExceptionTest check_exception) {
|
|||
check.template operator()<"hello {}">(SV("hello 42"), static_cast<unsigned long long>(42));
|
||||
#ifndef TEST_HAS_NO_INT128
|
||||
check.template operator()<"hello {}">(SV("hello 42"), static_cast<__uint128_t>(42));
|
||||
{
|
||||
// Note 128-bit support is only partly implemented test the range
|
||||
// conditions here.
|
||||
static constexpr auto fmt = string_literal("{}");
|
||||
std::basic_string<CharT> max = std::format(fmt.template sv<CharT>(), std::numeric_limits<unsigned long long>::max());
|
||||
check.template operator()<"{}">(std::basic_string_view<CharT>(max),
|
||||
static_cast<__uint128_t>(std::numeric_limits<unsigned long long>::max()));
|
||||
check_exception("128-bit value is outside of implemented range", SV("{}"),
|
||||
static_cast<__uint128_t>(std::numeric_limits<unsigned long long>::max()) + 1);
|
||||
}
|
||||
#endif
|
||||
format_test_unsigned_integer<CharT>(check, check_exception);
|
||||
|
||||
|
|
Loading…
Reference in New Issue