xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Support/FormatProviders.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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:
parseNumericPrecision(StringRef Str)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(10, 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>(99u, Prec);
75     }
76     return Result;
77   }
78 
consumeHexStyle(StringRef & Str)79   static std::optional<HexPrintStyle> consumeHexStyle(StringRef &Str) {
80     if (!Str.starts_with_insensitive("x"))
81       return std::nullopt;
82 
83     if (Str.consume_front("x-"))
84       return HexPrintStyle::Lower;
85     if (Str.consume_front("X-"))
86       return HexPrintStyle::Upper;
87     if (Str.consume_front("x+") || Str.consume_front("x"))
88       return HexPrintStyle::PrefixLower;
89     if (!Str.consume_front("X+"))
90       Str.consume_front("X");
91     return HexPrintStyle::PrefixUpper;
92   }
93 
consumeNumHexDigits(StringRef & Str,HexPrintStyle Style,size_t Default)94   static size_t consumeNumHexDigits(StringRef &Str, HexPrintStyle Style,
95                                     size_t Default) {
96     Str.consumeInteger(10, Default);
97     if (isPrefixedHexStyle(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(Style)) {
137       Digits = consumeNumHexDigits(Style, *HS, 0);
138       write_hex(Stream, V, *HS, Digits);
139       return;
140     }
141 
142     IntegerStyle IS = IntegerStyle::Integer;
143     if (Style.consume_front("N") || Style.consume_front("n"))
144       IS = IntegerStyle::Number;
145     else if (Style.consume_front("D") || Style.consume_front("d"))
146       IS = IntegerStyle::Integer;
147 
148     Style.consumeInteger(10, 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(Style))
185       HS = *consumed;
186     size_t Digits = consumeNumHexDigits(Style, HS, sizeof(void *) * 2);
187     write_hex(Stream, reinterpret_cast<std::uintptr_t>(V), HS, 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(10, N)) {
208       assert(false && "Style is not a valid integer");
209     }
210     llvm::StringRef S = V;
211     Stream << S.substr(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.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(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("Y", B ? "YES" : "NO")
270                   .Case("y", B ? "yes" : "no")
271                   .CaseLower("D", B ? "1" : "0")
272                   .Case("T", B ? "TRUE" : "FALSE")
273                   .Cases("t", "", B ? "true" : "false")
274                   .Default(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("P") || Style.consume_front("p"))
308       S = FloatStyle::Percent;
309     else if (Style.consume_front("F") || Style.consume_front("f"))
310       S = FloatStyle::Fixed;
311     else if (Style.consume_front("E"))
312       S = FloatStyle::ExponentUpper;
313     else if (Style.consume_front("e"))
314       S = FloatStyle::Exponent;
315     else
316       S = FloatStyle::Fixed;
317 
318     std::optional<size_t> Precision = parseNumericPrecision(Style);
319     if (!Precision)
320       Precision = getDefaultPrecision(S);
321 
322     write_double(Stream, static_cast<double>(V), 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(D[1]);
381       if (End == StringRef::npos) {
382         assert(false && "Missing range option end delimeter!");
383         return Default;
384       }
385       StringRef Result = Style.slice(1, End);
386       Style = Style.drop_front(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, '$', ", ");
395     StringRef Args = consumeOneOption(Style, '@', "");
396     assert(Style.empty() && "Unexpected text in range option string!");
397     return std::make_pair(Sep, 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(Sep, 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