[libcxx-commits] [libcxx] 49d4fee - [libc++][format] Removes test redundancy.

Mark de Wever via libcxx-commits libcxx-commits at lists.llvm.org
Thu Dec 22 10:39:32 PST 2022


Author: Mark de Wever
Date: 2022-12-22T19:39:27+01:00
New Revision: 49d4fee9940f5e1273cc0ae30da82df9c1437706

URL: https://github.com/llvm/llvm-project/commit/49d4fee9940f5e1273cc0ae30da82df9c1437706
DIFF: https://github.com/llvm/llvm-project/commit/49d4fee9940f5e1273cc0ae30da82df9c1437706.diff

LOG: [libc++][format] Removes test redundancy.

The format function test serve two purposes:
- Test whether all format functions work in general.
- Test whether all formatting rules are implemented correctly.

At the moment the *pass.cpp tests do both. These tests are quite slow,
while testing all rules for all functions doesn't add much coverage.

There are two execution modi of the format functions:
- run-time validation in the vformat functions.
- compile-time validation in the other function.

So instead of running all tests for all functions, they are only used for
format.pass.cpp and vformat.pass.cpp still do all tests.

The other tests do a smaller set of test, just to make sure they work in the
basics.

Running the format tests using one thread:
- before 00:04:16
- after  00:02:14

The slow tests were also reported in
https::llvm.org/PR58141

Also split a generic part of the test to a generic support header. This
allows these parts to be reused in the range-based formatter tests.

Reviewed By: #libc, ldionne

Differential Revision: https://reviews.llvm.org/D140115

Added: 
    libcxx/test/support/format.functions.common.h

Modified: 
    libcxx/test/std/utilities/format/format.functions/format.locale.pass.cpp
    libcxx/test/std/utilities/format/format.functions/format.pass.cpp
    libcxx/test/std/utilities/format/format.functions/format_tests.h
    libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp
    libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp
    libcxx/test/std/utilities/format/format.functions/format_to_n.locale.pass.cpp
    libcxx/test/std/utilities/format/format.functions/format_to_n.pass.cpp
    libcxx/test/std/utilities/format/format.functions/formatted_size.locale.pass.cpp
    libcxx/test/std/utilities/format/format.functions/formatted_size.pass.cpp
    libcxx/test/std/utilities/format/format.functions/vformat.locale.pass.cpp
    libcxx/test/std/utilities/format/format.functions/vformat.pass.cpp
    libcxx/test/std/utilities/format/format.functions/vformat_to.locale.pass.cpp
    libcxx/test/std/utilities/format/format.functions/vformat_to.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/test/std/utilities/format/format.functions/format.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format.locale.pass.cpp
index a50c416f89de2..76d4b35f90cfc 100644
--- a/libcxx/test/std/utilities/format/format.functions/format.locale.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/format.locale.pass.cpp
@@ -47,11 +47,11 @@ auto test_exception = []<class CharT, class... Args>(std::string_view, std::basi
 };
 
 int main(int, char**) {
-  format_tests<char>(test, test_exception);
+  format_tests<char, execution_modus::full>(test, test_exception);
 
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   format_tests_char_to_wchar_t(test);
-  format_tests<wchar_t>(test, test_exception);
+  format_tests<wchar_t, execution_modus::full>(test, test_exception);
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/utilities/format/format.functions/format.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format.pass.cpp
index 1bcc216a6e9f9..271007803af8d 100644
--- a/libcxx/test/std/utilities/format/format.functions/format.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/format.pass.cpp
@@ -56,11 +56,11 @@ auto test_exception = []<class CharT, class... Args>(std::string_view, std::basi
 };
 
 int main(int, char**) {
-  format_tests<char>(test, test_exception);
+  format_tests<char, execution_modus::full>(test, test_exception);
 
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   format_tests_char_to_wchar_t(test);
-  format_tests<wchar_t>(test, test_exception);
+  format_tests<wchar_t, execution_modus::full>(test, test_exception);
 #endif
 
   return 0;

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 d5de3aa11f52a..86d11f2c26be6 100644
--- a/libcxx/test/std/utilities/format/format.functions/format_tests.h
+++ b/libcxx/test/std/utilities/format/format.functions/format_tests.h
@@ -17,126 +17,15 @@
 #include <cstdint>
 #include <iterator>
 
-#include "make_string.h"
 #include "string_literal.h"
 #include "test_macros.h"
+#include "format.functions.common.h"
 
 // In this file the following template types are used:
 // TestFunction must be callable as check(expected-result, string-to-format, args-to-format...)
 // ExceptionTest must be callable as check_exception(expected-exception, string-to-format, args-to-format...)
 
-#define STR(S) MAKE_STRING(CharT, S)
-#define SV(S) MAKE_STRING_VIEW(CharT, S)
-#define CSTR(S) MAKE_CSTRING(CharT, S)
-
-template <class T>
-struct context {};
-
-template <>
-struct context<char> {
-  using type = std::format_context;
-};
-
-#ifndef TEST_HAS_NO_WIDE_CHARACTERS
-template <>
-struct context<wchar_t> {
-  using type = std::wformat_context;
-};
-#endif
-
-template <class T>
-using context_t = typename context<T>::type;
-
-// A user-defined type used to test the handle formatter.
-enum class status : uint16_t { foo = 0xAAAA, bar = 0x5555, foobar = 0xAA55 };
-
-// The formatter for a user-defined type used to test the handle formatter.
-template <class CharT>
-struct std::formatter<status, CharT> {
-  int type = 0;
-
-  constexpr auto parse(basic_format_parse_context<CharT>& parse_ctx) -> decltype(parse_ctx.begin()) {
-    auto begin = parse_ctx.begin();
-    auto end = parse_ctx.end();
-    if (begin == end)
-      return begin;
-
-    switch (*begin) {
-    case CharT('x'):
-      break;
-    case CharT('X'):
-      type = 1;
-      break;
-    case CharT('s'):
-      type = 2;
-      break;
-    case CharT('}'):
-      return begin;
-    default:
-      throw_format_error("The format-spec type has a type not supported for a status argument");
-    }
-
-    ++begin;
-    if (begin != end && *begin != CharT('}'))
-      throw_format_error("The format-spec should consume the input or end with a '}'");
-
-    return begin;
-  }
-
-  template <class Out>
-  auto format(status s, basic_format_context<Out, CharT>& ctx) const -> decltype(ctx.out()) {
-    const char* names[] = {"foo", "bar", "foobar"};
-    char buffer[7];
-    const char* begin = names[0];
-    const char* end = names[0];
-    switch (type) {
-    case 0:
-      begin = buffer;
-      buffer[0] = '0';
-      buffer[1] = 'x';
-      end = std::to_chars(&buffer[2], std::end(buffer), static_cast<uint16_t>(s), 16).ptr;
-      buffer[6] = '\0';
-      break;
-
-    case 1:
-      begin = buffer;
-      buffer[0] = '0';
-      buffer[1] = 'X';
-      end = std::to_chars(&buffer[2], std::end(buffer), static_cast<uint16_t>(s), 16).ptr;
-      std::transform(static_cast<const char*>(&buffer[2]), end, &buffer[2], [](char c) {
-        return static_cast<char>(std::toupper(c)); });
-      buffer[6] = '\0';
-      break;
-
-    case 2:
-      switch (s) {
-      case status::foo:
-        begin = names[0];
-        break;
-      case status::bar:
-        begin = names[1];
-        break;
-      case status::foobar:
-        begin = names[2];
-        break;
-      }
-      end = begin + strlen(begin);
-      break;
-    }
-
-    return std::copy(begin, end, ctx.out());
-  }
-
-private:
-  void throw_format_error(const char* s) {
-#ifndef TEST_HAS_NO_EXCEPTIONS
-    throw std::format_error(s);
-#else
-    (void)s;
-    std::abort();
-#endif
-  }
-};
+enum class execution_modus { partial, full };
 
 template <class CharT>
 std::vector<std::basic_string_view<CharT>> invalid_types(std::string_view valid) {
@@ -2722,7 +2611,7 @@ void format_test_buffer_optimizations(TestFunction check) {
   check(std::basic_string_view<CharT>{fill + str}, SV("{:*>{}}"), str, minimum + str.size());
 }
 
-template <class CharT, class TestFunction, class ExceptionTest>
+template <class CharT, execution_modus modus, class TestFunction, class ExceptionTest>
 void format_tests(TestFunction check, ExceptionTest check_exception) {
   // *** Test escaping  ***
 
@@ -2797,8 +2686,10 @@ void format_tests(TestFunction check, ExceptionTest check_exception) {
         CharT('A'),
         CharT('Z'),
         CharT('!'));
-  format_test_char<CharT>(check, check_exception);
-  format_test_char_as_integer<CharT>(check, check_exception);
+  if constexpr (modus == execution_modus::full) {
+    format_test_char<CharT>(check, check_exception);
+    format_test_char_as_integer<CharT>(check, check_exception);
+  }
 
   // *** Test string format argument ***
   {
@@ -2820,13 +2711,16 @@ void format_tests(TestFunction check, ExceptionTest check_exception) {
     std::basic_string_view<CharT> data = buffer;
     check(SV("hello world"), SV("hello {}"), data);
   }
-  format_string_tests<CharT>(check, check_exception);
+  if constexpr (modus == execution_modus::full)
+    format_string_tests<CharT>(check, check_exception);
 
   // *** Test Boolean format argument ***
   check(SV("hello false true"), SV("hello {} {}"), false, true);
 
-  format_test_bool<CharT>(check, check_exception);
-  format_test_bool_as_integer<CharT>(check, check_exception);
+  if constexpr (modus == execution_modus::full) {
+    format_test_bool<CharT>(check, check_exception);
+    format_test_bool_as_integer<CharT>(check, check_exception);
+  }
 
   // *** Test signed integral format argument ***
   check(SV("hello 42"), SV("hello {}"), static_cast<signed char>(42));
@@ -2837,7 +2731,8 @@ void format_tests(TestFunction check, ExceptionTest check_exception) {
 #ifndef TEST_HAS_NO_INT128
   check(SV("hello 42"), SV("hello {}"), static_cast<__int128_t>(42));
 #endif
-  format_test_signed_integer<CharT>(check, check_exception);
+  if constexpr (modus == execution_modus::full)
+    format_test_signed_integer<CharT>(check, check_exception);
 
   // ** Test unsigned integral format argument ***
   check(SV("hello 42"), SV("hello {}"), static_cast<unsigned char>(42));
@@ -2848,25 +2743,29 @@ void format_tests(TestFunction check, ExceptionTest check_exception) {
 #ifndef TEST_HAS_NO_INT128
   check(SV("hello 42"), SV("hello {}"), static_cast<__uint128_t>(42));
 #endif
-  format_test_unsigned_integer<CharT>(check, check_exception);
+  if constexpr (modus == execution_modus::full)
+    format_test_unsigned_integer<CharT>(check, check_exception);
 
   // *** Test floating point format argument ***
   check(SV("hello 42"), SV("hello {}"), static_cast<float>(42));
   check(SV("hello 42"), SV("hello {}"), static_cast<double>(42));
   check(SV("hello 42"), SV("hello {}"), static_cast<long double>(42));
-  format_test_floating_point<CharT>(check, check_exception);
+  if constexpr (modus == execution_modus::full)
+    format_test_floating_point<CharT>(check, check_exception);
 
   // *** Test pointer formater argument ***
   check(SV("hello 0x0"), SV("hello {}"), nullptr);
   check(SV("hello 0x42"), SV("hello {}"), reinterpret_cast<void*>(0x42));
   check(SV("hello 0x42"), SV("hello {}"), reinterpret_cast<const void*>(0x42));
-  format_test_pointer<CharT>(check, check_exception);
+  if constexpr (modus == execution_modus::full)
+    format_test_pointer<CharT>(check, check_exception);
 
   // *** Test handle formatter argument ***
   format_test_handle<CharT>(check, check_exception);
 
   // *** Test the interal buffer optimizations ***
-  format_test_buffer_optimizations<CharT>(check);
+  if constexpr (modus == execution_modus::full)
+    format_test_buffer_optimizations<CharT>(check);
 }
 
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
@@ -2877,4 +2776,4 @@ void format_tests_char_to_wchar_t(TestFunction check) {
 }
 #endif
 
-#endif
+#endif // TEST_STD_UTILITIES_FORMAT_FORMAT_FUNCTIONS_FORMAT_TESTS_H

diff  --git a/libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp
index 1bd6dc813a33f..f497e2d1ee3c3 100644
--- a/libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/format_to.locale.pass.cpp
@@ -70,11 +70,11 @@ auto test_exception = []<class CharT, class... Args>(std::string_view, std::basi
 };
 
 int main(int, char**) {
-  format_tests<char>(test, test_exception);
+  format_tests<char, execution_modus::partial>(test, test_exception);
 
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   format_tests_char_to_wchar_t(test);
-  format_tests<wchar_t>(test, test_exception);
+  format_tests<wchar_t, execution_modus::partial>(test, test_exception);
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp
index 16d2878554ff5..90615f7ff38d9 100644
--- a/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/format_to.pass.cpp
@@ -66,11 +66,11 @@ auto test_exception = []<class CharT, class... Args>(std::string_view, std::basi
 };
 
 int main(int, char**) {
-  format_tests<char>(test, test_exception);
+  format_tests<char, execution_modus::partial>(test, test_exception);
 
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   format_tests_char_to_wchar_t(test);
-  format_tests<wchar_t>(test, test_exception);
+  format_tests<wchar_t, execution_modus::partial>(test, test_exception);
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/utilities/format/format.functions/format_to_n.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format_to_n.locale.pass.cpp
index ee16552440047..8a9a5395dcc49 100644
--- a/libcxx/test/std/utilities/format/format.functions/format_to_n.locale.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/format_to_n.locale.pass.cpp
@@ -106,11 +106,11 @@ auto test_exception = []<class CharT, class... Args>(std::string_view, std::basi
 };
 
 int main(int, char**) {
-  format_tests<char>(test, test_exception);
+  format_tests<char, execution_modus::partial>(test, test_exception);
 
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   format_tests_char_to_wchar_t(test);
-  format_tests<wchar_t>(test, test_exception);
+  format_tests<wchar_t, execution_modus::partial>(test, test_exception);
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/utilities/format/format.functions/format_to_n.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format_to_n.pass.cpp
index e758e6533b7e5..8ce91da8ca417 100644
--- a/libcxx/test/std/utilities/format/format.functions/format_to_n.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/format_to_n.pass.cpp
@@ -100,11 +100,11 @@ auto test_exception = []<class CharT, class... Args>(std::string_view, std::basi
 };
 
 int main(int, char**) {
-  format_tests<char>(test, test_exception);
+  format_tests<char, execution_modus::partial>(test, test_exception);
 
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   format_tests_char_to_wchar_t(test);
-  format_tests<wchar_t>(test, test_exception);
+  format_tests<wchar_t, execution_modus::partial>(test, test_exception);
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/utilities/format/format.functions/formatted_size.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/formatted_size.locale.pass.cpp
index 1317f7f0e6bc9..625b99f0a8de1 100644
--- a/libcxx/test/std/utilities/format/format.functions/formatted_size.locale.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/formatted_size.locale.pass.cpp
@@ -44,11 +44,11 @@ auto test_exception = []<class CharT, class... Args>(std::string_view, std::basi
 };
 
 int main(int, char**) {
-  format_tests<char>(test, test_exception);
+  format_tests<char, execution_modus::partial>(test, test_exception);
 
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   format_tests_char_to_wchar_t(test);
-  format_tests<wchar_t>(test, test_exception);
+  format_tests<wchar_t, execution_modus::partial>(test, test_exception);
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/utilities/format/format.functions/formatted_size.pass.cpp b/libcxx/test/std/utilities/format/format.functions/formatted_size.pass.cpp
index 8f0eae03488fe..6a627ec3fecfe 100644
--- a/libcxx/test/std/utilities/format/format.functions/formatted_size.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/formatted_size.pass.cpp
@@ -41,11 +41,11 @@ auto test_exception = []<class CharT, class... Args>(std::string_view, std::basi
 };
 
 int main(int, char**) {
-  format_tests<char>(test, test_exception);
+  format_tests<char, execution_modus::partial>(test, test_exception);
 
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   format_tests_char_to_wchar_t(test);
-  format_tests<wchar_t>(test, test_exception);
+  format_tests<wchar_t, execution_modus::partial>(test, test_exception);
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/utilities/format/format.functions/vformat.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/vformat.locale.pass.cpp
index c2d53de561a1e..11bf67f064904 100644
--- a/libcxx/test/std/utilities/format/format.functions/vformat.locale.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/vformat.locale.pass.cpp
@@ -48,11 +48,11 @@ auto test_exception =
     };
 
 int main(int, char**) {
-  format_tests<char>(test, test_exception);
+  format_tests<char, execution_modus::full>(test, test_exception);
 
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   format_tests_char_to_wchar_t(test);
-  format_tests<wchar_t>(test, test_exception);
+  format_tests<wchar_t, execution_modus::full>(test, test_exception);
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/utilities/format/format.functions/vformat.pass.cpp b/libcxx/test/std/utilities/format/format.functions/vformat.pass.cpp
index 7692e09695540..d1156158b2695 100644
--- a/libcxx/test/std/utilities/format/format.functions/vformat.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/vformat.pass.cpp
@@ -22,6 +22,7 @@
 #include "test_macros.h"
 #include "format_tests.h"
 #include "string_literal.h"
+
 auto test = []<class CharT, class... Args>(
                 std::basic_string_view<CharT> expected, std::basic_string_view<CharT> fmt, Args&&... args) constexpr {
   std::basic_string<CharT> out = std::vformat(fmt, std::make_format_args<context_t<CharT>>(args...));
@@ -46,11 +47,11 @@ auto test_exception =
     };
 
 int main(int, char**) {
-  format_tests<char>(test, test_exception);
+  format_tests<char, execution_modus::full>(test, test_exception);
 
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   format_tests_char_to_wchar_t(test);
-  format_tests<wchar_t>(test, test_exception);
+  format_tests<wchar_t, execution_modus::full>(test, test_exception);
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/utilities/format/format.functions/vformat_to.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/vformat_to.locale.pass.cpp
index 3d1f4181d373e..993f19a02d9ce 100644
--- a/libcxx/test/std/utilities/format/format.functions/vformat_to.locale.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/vformat_to.locale.pass.cpp
@@ -77,11 +77,11 @@ auto test_exception =
     };
 
 int main(int, char**) {
-  format_tests<char>(test, test_exception);
+  format_tests<char, execution_modus::partial>(test, test_exception);
 
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   format_tests_char_to_wchar_t(test);
-  format_tests<wchar_t>(test, test_exception);
+  format_tests<wchar_t, execution_modus::partial>(test, test_exception);
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/utilities/format/format.functions/vformat_to.pass.cpp b/libcxx/test/std/utilities/format/format.functions/vformat_to.pass.cpp
index 8a8bf6f44aec4..0574d49e59451 100644
--- a/libcxx/test/std/utilities/format/format.functions/vformat_to.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/vformat_to.pass.cpp
@@ -74,11 +74,11 @@ auto test_exception =
     };
 
 int main(int, char**) {
-  format_tests<char>(test, test_exception);
+  format_tests<char, execution_modus::partial>(test, test_exception);
 
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
   format_tests_char_to_wchar_t(test);
-  format_tests<wchar_t>(test, test_exception);
+  format_tests<wchar_t, execution_modus::partial>(test, test_exception);
 #endif
 
   return 0;

diff  --git a/libcxx/test/support/format.functions.common.h b/libcxx/test/support/format.functions.common.h
new file mode 100644
index 0000000000000..fa107ba5dc44a
--- /dev/null
+++ b/libcxx/test/support/format.functions.common.h
@@ -0,0 +1,130 @@
+//===----------------------------------------------------------------------===//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_SUPPORT_FORMAT_FUNCTIONS_COMMON_H
+#define TEST_SUPPORT_FORMAT_FUNCTIONS_COMMON_H
+
+// Contains the common part of the formatter tests for 
diff erent papers.
+
+#include <format>
+
+#include "make_string.h"
+
+#define STR(S) MAKE_STRING(CharT, S)
+#define SV(S) MAKE_STRING_VIEW(CharT, S)
+#define CSTR(S) MAKE_CSTRING(CharT, S)
+
+template <class T>
+struct context {};
+
+template <>
+struct context<char> {
+  using type = std::format_context;
+};
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+template <>
+struct context<wchar_t> {
+  using type = std::wformat_context;
+};
+#endif
+
+template <class T>
+using context_t = typename context<T>::type;
+
+// A user-defined type used to test the handle formatter.
+enum class status : uint16_t { foo = 0xAAAA, bar = 0x5555, foobar = 0xAA55 };
+
+// The formatter for a user-defined type used to test the handle formatter.
+template <class CharT>
+struct std::formatter<status, CharT> {
+  int type = 0;
+
+  constexpr auto parse(basic_format_parse_context<CharT>& parse_ctx) -> decltype(parse_ctx.begin()) {
+    auto begin = parse_ctx.begin();
+    auto end = parse_ctx.end();
+    if (begin == end)
+      return begin;
+
+    switch (*begin) {
+    case CharT('x'):
+      break;
+    case CharT('X'):
+      type = 1;
+      break;
+    case CharT('s'):
+      type = 2;
+      break;
+    case CharT('}'):
+      return begin;
+    default:
+      throw_format_error("The format-spec type has a type not supported for a status argument");
+    }
+
+    ++begin;
+    if (begin != end && *begin != CharT('}'))
+      throw_format_error("The format-spec should consume the input or end with a '}'");
+
+    return begin;
+  }
+
+  template <class Out>
+  auto format(status s, basic_format_context<Out, CharT>& ctx) const -> decltype(ctx.out()) {
+    const char* names[] = {"foo", "bar", "foobar"};
+    char buffer[7];
+    const char* begin = names[0];
+    const char* end = names[0];
+    switch (type) {
+    case 0:
+      begin = buffer;
+      buffer[0] = '0';
+      buffer[1] = 'x';
+      end = std::to_chars(&buffer[2], std::end(buffer), static_cast<uint16_t>(s), 16).ptr;
+      buffer[6] = '\0';
+      break;
+
+    case 1:
+      begin = buffer;
+      buffer[0] = '0';
+      buffer[1] = 'X';
+      end = std::to_chars(&buffer[2], std::end(buffer), static_cast<uint16_t>(s), 16).ptr;
+      std::transform(static_cast<const char*>(&buffer[2]), end, &buffer[2], [](char c) {
+        return static_cast<char>(std::toupper(c)); });
+      buffer[6] = '\0';
+      break;
+
+    case 2:
+      switch (s) {
+      case status::foo:
+        begin = names[0];
+        break;
+      case status::bar:
+        begin = names[1];
+        break;
+      case status::foobar:
+        begin = names[2];
+        break;
+      }
+      end = begin + strlen(begin);
+      break;
+    }
+
+    return std::copy(begin, end, ctx.out());
+  }
+
+private:
+  void throw_format_error(const char* s) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+    throw std::format_error(s);
+#else
+    (void)s;
+    std::abort();
+#endif
+  }
+};
+
+#endif // TEST_SUPPORT_FORMAT_FUNCTIONS_COMMON_H


        


More information about the libcxx-commits mailing list