[libcxx-commits] [libcxx] 0857a02 - [libc++][format] Implements 128-bit support.
Mark de Wever via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Jul 7 08:36:07 PDT 2022
Author: Mark de Wever
Date: 2022-07-07T17:36:03+02:00
New Revision: 0857a02ef07c1e6467728f504105d80ed1b6fe4a
URL: https://github.com/llvm/llvm-project/commit/0857a02ef07c1e6467728f504105d80ed1b6fe4a
DIFF: https://github.com/llvm/llvm-project/commit/0857a02ef07c1e6467728f504105d80ed1b6fe4a.diff
LOG: [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
Added:
Modified:
libcxx/include/__format/formatter_integer.h
libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.signed_integral.pass.cpp
libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.unsigned_integral.pass.cpp
libcxx/test/std/utilities/format/format.functions/format_tests.h
Removed:
################################################################################
diff --git a/libcxx/include/__format/formatter_integer.h b/libcxx/include/__format/formatter_integer.h
index 5d11f8d1d9902..0281b4f2fa679 100644
--- a/libcxx/include/__format/formatter_integer.h
+++ b/libcxx/include/__format/formatter_integer.h
@@ -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
diff --git a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.signed_integral.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.signed_integral.pass.cpp
index 285f28ef3fad5..a241d374708b9 100644
--- a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.signed_integral.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.signed_integral.pass.cpp
@@ -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>
diff --git a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.unsigned_integral.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.unsigned_integral.pass.cpp
index cae39122b87fb..c3e426fcba1cc 100644
--- a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.unsigned_integral.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.unsigned_integral.pass.cpp
@@ -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>
diff --git a/libcxx/test/std/utilities/format/format.functions/format_tests.h b/libcxx/test/std/utilities/format/format.functions/format_tests.h
index f6da95b55a07b..6a019d06fd4e1 100644
--- a/libcxx/test/std/utilities/format/format.functions/format_tests.h
+++ b/libcxx/test/std/utilities/format/format.functions/format_tests.h
@@ -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);
More information about the libcxx-commits
mailing list