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