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(10, 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>(99u, Prec);
74     }
75     return Result;
76   }
77 
78   static bool consumeHexStyle(StringRef &Str, HexPrintStyle &Style) {
79     if (!Str.starts_with_insensitive("x"))
80       return false;
81 
82     if (Str.consume_front("x-"))
83       Style = HexPrintStyle::Lower;
84     else if (Str.consume_front("X-"))
85       Style = HexPrintStyle::Upper;
86     else if (Str.consume_front("x+") || Str.consume_front("x"))
87       Style = HexPrintStyle::PrefixLower;
88     else if (Str.consume_front("X+") || Str.consume_front("X"))
89       Style = HexPrintStyle::PrefixUpper;
90     return true;
91   }
92 
93   static size_t consumeNumHexDigits(StringRef &Str, HexPrintStyle Style,
94                                     size_t Default) {
95     Str.consumeInteger(10, Default);
96     if (isPrefixedHexStyle(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(Style, HS)) {
136       Digits = consumeNumHexDigits(Style, HS, 0);
137       write_hex(Stream, V, HS, Digits);
138       return;
139     }
140 
141     IntegerStyle IS = IntegerStyle::Integer;
142     if (Style.consume_front("N") || Style.consume_front("n"))
143       IS = IntegerStyle::Number;
144     else if (Style.consume_front("D") || Style.consume_front("d"))
145       IS = IntegerStyle::Integer;
146 
147     Style.consumeInteger(10, 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(Style, HS);
184     size_t Digits = consumeNumHexDigits(Style, HS, sizeof(void *) * 2);
185     write_hex(Stream, reinterpret_cast<std::uintptr_t>(V), HS, 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(10, N)) {
206       assert(false && "Style is not a valid integer");
207     }
208     llvm::StringRef S = V;
209     Stream << S.substr(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.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(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("Y", B ? "YES" : "NO")
268                   .Case("y", B ? "yes" : "no")
269                   .CaseLower("D", B ? "1" : "0")
270                   .Case("T", B ? "TRUE" : "FALSE")
271                   .Cases("t", "", B ? "true" : "false")
272                   .Default(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("P") || Style.consume_front("p"))
306       S = FloatStyle::Percent;
307     else if (Style.consume_front("F") || Style.consume_front("f"))
308       S = FloatStyle::Fixed;
309     else if (Style.consume_front("E"))
310       S = FloatStyle::ExponentUpper;
311     else if (Style.consume_front("e"))
312       S = FloatStyle::Exponent;
313     else
314       S = FloatStyle::Fixed;
315 
316     std::optional<size_t> Precision = parseNumericPrecision(Style);
317     if (!Precision)
318       Precision = getDefaultPrecision(S);
319 
320     write_double(Stream, static_cast<double>(V), 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(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 = 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