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