1 | //===- FormatProviders.h - Formatters for common LLVM types -----*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file implements format providers for many common LLVM types, for example |
10 | // allowing precision and width specifiers for scalar and string types. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_SUPPORT_FORMATPROVIDERS_H |
15 | #define LLVM_SUPPORT_FORMATPROVIDERS_H |
16 | |
17 | #include "llvm/ADT/STLExtras.h" |
18 | #include "llvm/ADT/StringSwitch.h" |
19 | #include "llvm/ADT/Twine.h" |
20 | #include "llvm/Support/FormatVariadicDetails.h" |
21 | #include "llvm/Support/NativeFormatting.h" |
22 | |
23 | #include <array> |
24 | #include <optional> |
25 | #include <type_traits> |
26 | |
27 | namespace llvm { |
28 | namespace support { |
29 | namespace detail { |
30 | template <typename T> |
31 | struct use_integral_formatter |
32 | : public std::integral_constant< |
33 | bool, is_one_of<T, uint8_t, int16_t, uint16_t, int32_t, uint32_t, |
34 | int64_t, uint64_t, int, unsigned, long, unsigned long, |
35 | long long, unsigned long long>::value> {}; |
36 | |
37 | template <typename T> |
38 | struct use_char_formatter |
39 | : public std::integral_constant<bool, std::is_same_v<T, char>> {}; |
40 | |
41 | template <typename T> |
42 | struct is_cstring |
43 | : public std::integral_constant<bool, |
44 | is_one_of<T, char *, const char *>::value> { |
45 | }; |
46 | |
47 | template <typename T> |
48 | struct use_string_formatter |
49 | : public std::integral_constant<bool, |
50 | std::is_convertible_v<T, llvm::StringRef>> { |
51 | }; |
52 | |
53 | template <typename T> |
54 | struct use_pointer_formatter |
55 | : public std::integral_constant<bool, std::is_pointer_v<T> && |
56 | !is_cstring<T>::value> {}; |
57 | |
58 | template <typename T> |
59 | struct use_double_formatter |
60 | : public std::integral_constant<bool, std::is_floating_point_v<T>> {}; |
61 | |
62 | class HelperFunctions { |
63 | protected: |
64 | static std::optional<size_t> parseNumericPrecision(StringRef Str) { |
65 | size_t Prec; |
66 | std::optional<size_t> Result; |
67 | if (Str.empty()) |
68 | Result = std::nullopt; |
69 | else if (Str.getAsInteger(Radix: 10, Result&: Prec)) { |
70 | assert(false && "Invalid precision specifier" ); |
71 | Result = std::nullopt; |
72 | } else { |
73 | assert(Prec < 100 && "Precision out of range" ); |
74 | Result = std::min<size_t>(a: 99u, b: Prec); |
75 | } |
76 | return Result; |
77 | } |
78 | |
79 | static std::optional<HexPrintStyle> consumeHexStyle(StringRef &Str) { |
80 | if (!Str.starts_with_insensitive(Prefix: "x" )) |
81 | return std::nullopt; |
82 | |
83 | if (Str.consume_front(Prefix: "x-" )) |
84 | return HexPrintStyle::Lower; |
85 | if (Str.consume_front(Prefix: "X-" )) |
86 | return HexPrintStyle::Upper; |
87 | if (Str.consume_front(Prefix: "x+" ) || Str.consume_front(Prefix: "x" )) |
88 | return HexPrintStyle::PrefixLower; |
89 | if (!Str.consume_front(Prefix: "X+" )) |
90 | Str.consume_front(Prefix: "X" ); |
91 | return HexPrintStyle::PrefixUpper; |
92 | } |
93 | |
94 | static size_t (StringRef &Str, HexPrintStyle Style, |
95 | size_t Default) { |
96 | Str.consumeInteger(Radix: 10, Result&: Default); |
97 | if (isPrefixedHexStyle(S: Style)) |
98 | Default += 2; |
99 | return Default; |
100 | } |
101 | }; |
102 | } // namespace detail |
103 | } // namespace support |
104 | |
105 | /// Implementation of format_provider<T> for integral arithmetic types. |
106 | /// |
107 | /// The options string of an integral type has the grammar: |
108 | /// |
109 | /// integer_options :: [style][digits] |
110 | /// style :: <see table below> |
111 | /// digits :: <non-negative integer> 0-99 |
112 | /// |
113 | /// ========================================================================== |
114 | /// | style | Meaning | Example | Digits Meaning | |
115 | /// -------------------------------------------------------------------------- |
116 | /// | | | Input | Output | | |
117 | /// ========================================================================== |
118 | /// | x- | Hex no prefix, lower | 42 | 2a | Minimum # digits | |
119 | /// | X- | Hex no prefix, upper | 42 | 2A | Minimum # digits | |
120 | /// | x+ / x | Hex + prefix, lower | 42 | 0x2a | Minimum # digits | |
121 | /// | X+ / X | Hex + prefix, upper | 42 | 0x2A | Minimum # digits | |
122 | /// | N / n | Digit grouped number | 123456 | 123,456 | Ignored | |
123 | /// | D / d | Integer | 100000 | 100000 | Ignored | |
124 | /// | (empty) | Same as D / d | | | | |
125 | /// ========================================================================== |
126 | /// |
127 | |
128 | template <typename T> |
129 | struct format_provider< |
130 | T, std::enable_if_t<support::detail::use_integral_formatter<T>::value>> |
131 | : public support::detail::HelperFunctions { |
132 | private: |
133 | public: |
134 | static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) { |
135 | size_t Digits = 0; |
136 | if (std::optional<HexPrintStyle> HS = consumeHexStyle(Str&: Style)) { |
137 | Digits = consumeNumHexDigits(Str&: Style, Style: *HS, Default: 0); |
138 | write_hex(Stream, V, *HS, Digits); |
139 | return; |
140 | } |
141 | |
142 | IntegerStyle IS = IntegerStyle::Integer; |
143 | if (Style.consume_front(Prefix: "N" ) || Style.consume_front(Prefix: "n" )) |
144 | IS = IntegerStyle::Number; |
145 | else if (Style.consume_front(Prefix: "D" ) || Style.consume_front(Prefix: "d" )) |
146 | IS = IntegerStyle::Integer; |
147 | |
148 | Style.consumeInteger(Radix: 10, Result&: Digits); |
149 | assert(Style.empty() && "Invalid integral format style!" ); |
150 | write_integer(Stream, V, Digits, IS); |
151 | } |
152 | }; |
153 | |
154 | /// Implementation of format_provider<T> for integral pointer types. |
155 | /// |
156 | /// The options string of a pointer type has the grammar: |
157 | /// |
158 | /// pointer_options :: [style][precision] |
159 | /// style :: <see table below> |
160 | /// digits :: <non-negative integer> 0-sizeof(void*) |
161 | /// |
162 | /// ========================================================================== |
163 | /// | S | Meaning | Example | |
164 | /// -------------------------------------------------------------------------- |
165 | /// | | | Input | Output | |
166 | /// ========================================================================== |
167 | /// | x- | Hex no prefix, lower | 0xDEADBEEF | deadbeef | |
168 | /// | X- | Hex no prefix, upper | 0xDEADBEEF | DEADBEEF | |
169 | /// | x+ / x | Hex + prefix, lower | 0xDEADBEEF | 0xdeadbeef | |
170 | /// | X+ / X | Hex + prefix, upper | 0xDEADBEEF | 0xDEADBEEF | |
171 | /// | (empty) | Same as X+ / X | | | |
172 | /// ========================================================================== |
173 | /// |
174 | /// The default precision is the number of nibbles in a machine word, and in all |
175 | /// cases indicates the minimum number of nibbles to print. |
176 | template <typename T> |
177 | struct format_provider< |
178 | T, std::enable_if_t<support::detail::use_pointer_formatter<T>::value>> |
179 | : public support::detail::HelperFunctions { |
180 | private: |
181 | public: |
182 | static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) { |
183 | HexPrintStyle HS = HexPrintStyle::PrefixUpper; |
184 | if (std::optional<HexPrintStyle> consumed = consumeHexStyle(Str&: Style)) |
185 | HS = *consumed; |
186 | size_t Digits = consumeNumHexDigits(Str&: Style, Style: HS, Default: sizeof(void *) * 2); |
187 | write_hex(S&: Stream, N: reinterpret_cast<std::uintptr_t>(V), Style: HS, Width: Digits); |
188 | } |
189 | }; |
190 | |
191 | /// Implementation of format_provider<T> for c-style strings and string |
192 | /// objects such as std::string and llvm::StringRef. |
193 | /// |
194 | /// The options string of a string type has the grammar: |
195 | /// |
196 | /// string_options :: [length] |
197 | /// |
198 | /// where `length` is an optional integer specifying the maximum number of |
199 | /// characters in the string to print. If `length` is omitted, the string is |
200 | /// printed up to the null terminator. |
201 | |
202 | template <typename T> |
203 | struct format_provider< |
204 | T, std::enable_if_t<support::detail::use_string_formatter<T>::value>> { |
205 | static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) { |
206 | size_t N = StringRef::npos; |
207 | if (!Style.empty() && Style.getAsInteger(Radix: 10, Result&: N)) { |
208 | assert(false && "Style is not a valid integer" ); |
209 | } |
210 | llvm::StringRef S = V; |
211 | Stream << S.substr(Start: 0, N); |
212 | } |
213 | }; |
214 | |
215 | /// Implementation of format_provider<T> for llvm::Twine. |
216 | /// |
217 | /// This follows the same rules as the string formatter. |
218 | |
219 | template <> struct format_provider<Twine> { |
220 | static void format(const Twine &V, llvm::raw_ostream &Stream, |
221 | StringRef Style) { |
222 | format_provider<std::string>::format(V: V.str(), Stream, Style); |
223 | } |
224 | }; |
225 | |
226 | /// Implementation of format_provider<T> for characters. |
227 | /// |
228 | /// The options string of a character type has the grammar: |
229 | /// |
230 | /// char_options :: (empty) | [integer_options] |
231 | /// |
232 | /// If `char_options` is empty, the character is displayed as an ASCII |
233 | /// character. Otherwise, it is treated as an integer options string. |
234 | /// |
235 | template <typename T> |
236 | struct format_provider< |
237 | T, std::enable_if_t<support::detail::use_char_formatter<T>::value>> { |
238 | static void format(const char &V, llvm::raw_ostream &Stream, |
239 | StringRef Style) { |
240 | if (Style.empty()) |
241 | Stream << V; |
242 | else { |
243 | int X = static_cast<int>(V); |
244 | format_provider<int>::format(V: X, Stream, Style); |
245 | } |
246 | } |
247 | }; |
248 | |
249 | /// Implementation of format_provider<T> for type `bool` |
250 | /// |
251 | /// The options string of a boolean type has the grammar: |
252 | /// |
253 | /// bool_options :: "" | "Y" | "y" | "D" | "d" | "T" | "t" |
254 | /// |
255 | /// ================================== |
256 | /// | C | Meaning | |
257 | /// ================================== |
258 | /// | Y | YES / NO | |
259 | /// | y | yes / no | |
260 | /// | D / d | Integer 0 or 1 | |
261 | /// | T | TRUE / FALSE | |
262 | /// | t | true / false | |
263 | /// | (empty) | Equivalent to 't' | |
264 | /// ================================== |
265 | template <> struct format_provider<bool> { |
266 | static void format(const bool &B, llvm::raw_ostream &Stream, |
267 | StringRef Style) { |
268 | Stream << StringSwitch<const char *>(Style) |
269 | .Case(S: "Y" , Value: B ? "YES" : "NO" ) |
270 | .Case(S: "y" , Value: B ? "yes" : "no" ) |
271 | .CaseLower(S: "D" , Value: B ? "1" : "0" ) |
272 | .Case(S: "T" , Value: B ? "TRUE" : "FALSE" ) |
273 | .Cases(S0: "t" , S1: "" , Value: B ? "true" : "false" ) |
274 | .Default(Value: B ? "1" : "0" ); |
275 | } |
276 | }; |
277 | |
278 | /// Implementation of format_provider<T> for floating point types. |
279 | /// |
280 | /// The options string of a floating point type has the format: |
281 | /// |
282 | /// float_options :: [style][precision] |
283 | /// style :: <see table below> |
284 | /// precision :: <non-negative integer> 0-99 |
285 | /// |
286 | /// ===================================================== |
287 | /// | style | Meaning | Example | |
288 | /// ----------------------------------------------------- |
289 | /// | | | Input | Output | |
290 | /// ===================================================== |
291 | /// | P / p | Percentage | 0.05 | 5.00% | |
292 | /// | F / f | Fixed point | 1.0 | 1.00 | |
293 | /// | E | Exponential with E | 100000 | 1.0E+05 | |
294 | /// | e | Exponential with e | 100000 | 1.0e+05 | |
295 | /// | (empty) | Same as F / f | | | |
296 | /// ===================================================== |
297 | /// |
298 | /// The default precision is 6 for exponential (E / e) and 2 for everything |
299 | /// else. |
300 | |
301 | template <typename T> |
302 | struct format_provider< |
303 | T, std::enable_if_t<support::detail::use_double_formatter<T>::value>> |
304 | : public support::detail::HelperFunctions { |
305 | static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) { |
306 | FloatStyle S; |
307 | if (Style.consume_front(Prefix: "P" ) || Style.consume_front(Prefix: "p" )) |
308 | S = FloatStyle::Percent; |
309 | else if (Style.consume_front(Prefix: "F" ) || Style.consume_front(Prefix: "f" )) |
310 | S = FloatStyle::Fixed; |
311 | else if (Style.consume_front(Prefix: "E" )) |
312 | S = FloatStyle::ExponentUpper; |
313 | else if (Style.consume_front(Prefix: "e" )) |
314 | S = FloatStyle::Exponent; |
315 | else |
316 | S = FloatStyle::Fixed; |
317 | |
318 | std::optional<size_t> Precision = parseNumericPrecision(Str: Style); |
319 | if (!Precision) |
320 | Precision = getDefaultPrecision(Style: S); |
321 | |
322 | write_double(S&: Stream, D: static_cast<double>(V), Style: S, Precision); |
323 | } |
324 | }; |
325 | |
326 | namespace support { |
327 | namespace detail { |
328 | template <typename IterT> |
329 | using IterValue = typename std::iterator_traits<IterT>::value_type; |
330 | |
331 | template <typename IterT> |
332 | struct range_item_has_provider |
333 | : public std::integral_constant< |
334 | bool, |
335 | !support::detail::uses_missing_provider<IterValue<IterT>>::value> {}; |
336 | } // namespace detail |
337 | } // namespace support |
338 | |
339 | /// Implementation of format_provider<T> for ranges. |
340 | /// |
341 | /// This will print an arbitrary range as a delimited sequence of items. |
342 | /// |
343 | /// The options string of a range type has the grammar: |
344 | /// |
345 | /// range_style ::= [separator] [element_style] |
346 | /// separator ::= "$" delimeted_expr |
347 | /// element_style ::= "@" delimeted_expr |
348 | /// delimeted_expr ::= "[" expr "]" | "(" expr ")" | "<" expr ">" |
349 | /// expr ::= <any string not containing delimeter> |
350 | /// |
351 | /// where the separator expression is the string to insert between consecutive |
352 | /// items in the range and the argument expression is the Style specification to |
353 | /// be used when formatting the underlying type. The default separator if |
354 | /// unspecified is ' ' (space). The syntax of the argument expression follows |
355 | /// whatever grammar is dictated by the format provider or format adapter used |
356 | /// to format the value type. |
357 | /// |
358 | /// Note that attempting to format an `iterator_range<T>` where no format |
359 | /// provider can be found for T will result in a compile error. |
360 | /// |
361 | |
362 | template <typename IterT> class format_provider<llvm::iterator_range<IterT>> { |
363 | using value = typename std::iterator_traits<IterT>::value_type; |
364 | |
365 | static StringRef consumeOneOption(StringRef &Style, char Indicator, |
366 | StringRef Default) { |
367 | if (Style.empty()) |
368 | return Default; |
369 | if (Style.front() != Indicator) |
370 | return Default; |
371 | Style = Style.drop_front(); |
372 | if (Style.empty()) { |
373 | assert(false && "Invalid range style" ); |
374 | return Default; |
375 | } |
376 | |
377 | for (const char *D : std::array<const char *, 3>{"[]" , "<>" , "()" }) { |
378 | if (Style.front() != D[0]) |
379 | continue; |
380 | size_t End = Style.find_first_of(C: D[1]); |
381 | if (End == StringRef::npos) { |
382 | assert(false && "Missing range option end delimeter!" ); |
383 | return Default; |
384 | } |
385 | StringRef Result = Style.slice(Start: 1, End); |
386 | Style = Style.drop_front(N: End + 1); |
387 | return Result; |
388 | } |
389 | assert(false && "Invalid range style!" ); |
390 | return Default; |
391 | } |
392 | |
393 | static std::pair<StringRef, StringRef> parseOptions(StringRef Style) { |
394 | StringRef Sep = consumeOneOption(Style, Indicator: '$', Default: ", " ); |
395 | StringRef Args = consumeOneOption(Style, Indicator: '@', Default: "" ); |
396 | assert(Style.empty() && "Unexpected text in range option string!" ); |
397 | return std::make_pair(x&: Sep, y&: Args); |
398 | } |
399 | |
400 | public: |
401 | static_assert(support::detail::range_item_has_provider<IterT>::value, |
402 | "Range value_type does not have a format provider!" ); |
403 | static void format(const llvm::iterator_range<IterT> &V, |
404 | llvm::raw_ostream &Stream, StringRef Style) { |
405 | StringRef Sep; |
406 | StringRef ArgStyle; |
407 | std::tie(args&: Sep, args&: ArgStyle) = parseOptions(Style); |
408 | auto Begin = V.begin(); |
409 | auto End = V.end(); |
410 | if (Begin != End) { |
411 | auto Adapter = support::detail::build_format_adapter(*Begin); |
412 | Adapter.format(Stream, ArgStyle); |
413 | ++Begin; |
414 | } |
415 | while (Begin != End) { |
416 | Stream << Sep; |
417 | auto Adapter = support::detail::build_format_adapter(*Begin); |
418 | Adapter.format(Stream, ArgStyle); |
419 | ++Begin; |
420 | } |
421 | } |
422 | }; |
423 | } // namespace llvm |
424 | |
425 | #endif |
426 | |