[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