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