1 //===----------------------------------------------------------------------===// 2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 3 // See https://llvm.org/LICENSE.txt for license information. 4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 5 // 6 //===----------------------------------------------------------------------===// 7 8 #ifndef TEST_SUPPORT_FORMAT_FUNCTIONS_COMMON_H 9 #define TEST_SUPPORT_FORMAT_FUNCTIONS_COMMON_H 10 11 // Contains the common part of the formatter tests for different papers. 12 13 #include <format> 14 15 #include "make_string.h" 16 17 #define STR(S) MAKE_STRING(CharT, S) 18 #define SV(S) MAKE_STRING_VIEW(CharT, S) 19 #define CSTR(S) MAKE_CSTRING(CharT, S) 20 21 template <class T> 22 struct context {}; 23 24 template <> 25 struct context<char> { 26 using type = std::format_context; 27 }; 28 29 #ifndef TEST_HAS_NO_WIDE_CHARACTERS 30 template <> 31 struct context<wchar_t> { 32 using type = std::wformat_context; 33 }; 34 #endif 35 36 template <class T> 37 using context_t = typename context<T>::type; 38 39 // A user-defined type used to test the handle formatter. 40 enum class status : uint16_t { foo = 0xAAAA, bar = 0x5555, foobar = 0xAA55 }; 41 42 // The formatter for a user-defined type used to test the handle formatter. 43 template <class CharT> 44 struct std::formatter<status, CharT> { 45 int type = 0; 46 47 constexpr auto parse(basic_format_parse_context<CharT>& parse_ctx) -> decltype(parse_ctx.begin()) { 48 auto begin = parse_ctx.begin(); 49 auto end = parse_ctx.end(); 50 if (begin == end) 51 return begin; 52 53 switch (*begin) { 54 case CharT('x'): 55 break; 56 case CharT('X'): 57 type = 1; 58 break; 59 case CharT('s'): 60 type = 2; 61 break; 62 case CharT('}'): 63 return begin; 64 default: 65 throw_format_error("The format-spec type has a type not supported for a status argument"); 66 } 67 68 ++begin; 69 if (begin != end && *begin != CharT('}')) 70 throw_format_error("The format-spec should consume the input or end with a '}'"); 71 72 return begin; 73 } 74 75 template <class Out> 76 auto format(status s, basic_format_context<Out, CharT>& ctx) const -> decltype(ctx.out()) { 77 const char* names[] = {"foo", "bar", "foobar"}; 78 char buffer[7]; 79 const char* begin = names[0]; 80 const char* end = names[0]; 81 switch (type) { 82 case 0: 83 begin = buffer; 84 buffer[0] = '0'; 85 buffer[1] = 'x'; 86 end = std::to_chars(&buffer[2], std::end(buffer), static_cast<uint16_t>(s), 16).ptr; 87 buffer[6] = '\0'; 88 break; 89 90 case 1: 91 begin = buffer; 92 buffer[0] = '0'; 93 buffer[1] = 'X'; 94 end = std::to_chars(&buffer[2], std::end(buffer), static_cast<uint16_t>(s), 16).ptr; 95 std::transform(static_cast<const char*>(&buffer[2]), end, &buffer[2], [](char c) { 96 return static_cast<char>(std::toupper(c)); }); 97 buffer[6] = '\0'; 98 break; 99 100 case 2: 101 switch (s) { 102 case status::foo: 103 begin = names[0]; 104 break; 105 case status::bar: 106 begin = names[1]; 107 break; 108 case status::foobar: 109 begin = names[2]; 110 break; 111 } 112 end = begin + strlen(begin); 113 break; 114 } 115 116 return std::copy(begin, end, ctx.out()); 117 } 118 119 private: 120 void throw_format_error(const char* s) { 121 #ifndef TEST_HAS_NO_EXCEPTIONS 122 throw std::format_error(s); 123 #else 124 (void)s; 125 std::abort(); 126 #endif 127 } 128 }; 129 130 #endif // TEST_SUPPORT_FORMAT_FUNCTIONS_COMMON_H 131