• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- FormatProviders.h - Formatters for common LLVM types -----*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements format providers for many common LLVM types, for example
11 // allowing precision and width specifiers for scalar and string types.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_SUPPORT_FORMATPROVIDERS_H
16 #define LLVM_SUPPORT_FORMATPROVIDERS_H
17 
18 #include "llvm/ADT/Optional.h"
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/ADT/StringSwitch.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<
49           bool, is_one_of<T, llvm::StringRef, std::string>::value ||
50                     is_cstring<T>::value> {};
51 
52 template <typename T>
53 struct use_pointer_formatter
54     : public std::integral_constant<bool, std::is_pointer<T>::value &&
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<T>::value> {};
60 
61 class HelperFunctions {
62 protected:
parseNumericPrecision(StringRef Str)63   static Optional<size_t> parseNumericPrecision(StringRef Str) {
64     size_t Prec;
65     Optional<size_t> Result;
66     if (Str.empty())
67       Result = None;
68     else if (Str.getAsInteger(10, Prec)) {
69       assert(false && "Invalid precision specifier");
70       Result = None;
71     } else {
72       assert(Prec < 100 && "Precision out of range");
73       Result = std::min<size_t>(99u, Prec);
74     }
75     return Result;
76   }
77 
consumeHexStyle(StringRef & Str,HexPrintStyle & Style)78   static bool consumeHexStyle(StringRef &Str, HexPrintStyle &Style) {
79     if (!Str.startswith_lower("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 
consumeNumHexDigits(StringRef & Str,HexPrintStyle Style,size_t Default)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, typename std::enable_if<detail::use_integral_formatter<T>::value>::type>
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, typename std::enable_if<detail::use_pointer_formatter<T>::value>::type>
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, typename std::enable_if<detail::use_string_formatter<T>::value>::type> {
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 characters.
214 ///
215 /// The options string of a character type has the grammar:
216 ///
217 ///   char_options :: (empty) | [integer_options]
218 ///
219 /// If `char_options` is empty, the character is displayed as an ASCII
220 /// character.  Otherwise, it is treated as an integer options string.
221 ///
222 template <typename T>
223 struct format_provider<
224     T, typename std::enable_if<detail::use_char_formatter<T>::value>::type> {
225   static void format(const char &V, llvm::raw_ostream &Stream,
226                      StringRef Style) {
227     if (Style.empty())
228       Stream << V;
229     else {
230       int X = static_cast<int>(V);
231       format_provider<int>::format(X, Stream, Style);
232     }
233   }
234 };
235 
236 /// Implementation of format_provider<T> for type `bool`
237 ///
238 /// The options string of a boolean type has the grammar:
239 ///
240 ///   bool_options :: "" | "Y" | "y" | "D" | "d" | "T" | "t"
241 ///
242 ///   ==================================
243 ///   |    C    |     Meaning          |
244 ///   ==================================
245 ///   |    Y    |       YES / NO       |
246 ///   |    y    |       yes / no       |
247 ///   |  D / d  |    Integer 0 or 1    |
248 ///   |    T    |     TRUE / FALSE     |
249 ///   |    t    |     true / false     |
250 ///   | (empty) |   Equivalent to 't'  |
251 ///   ==================================
252 template <> struct format_provider<bool> {
253   static void format(const bool &B, llvm::raw_ostream &Stream,
254                      StringRef Style) {
255     Stream << StringSwitch<const char *>(Style)
256                   .Case("Y", B ? "YES" : "NO")
257                   .Case("y", B ? "yes" : "no")
258                   .CaseLower("D", B ? "1" : "0")
259                   .Case("T", B ? "TRUE" : "FALSE")
260                   .Cases("t", "", B ? "true" : "false")
261                   .Default(B ? "1" : "0");
262   }
263 };
264 
265 /// Implementation of format_provider<T> for floating point types.
266 ///
267 /// The options string of a floating point type has the format:
268 ///
269 ///   float_options   :: [style][precision]
270 ///   style           :: <see table below>
271 ///   precision       :: <non-negative integer> 0-99
272 ///
273 ///   =====================================================
274 ///   |  style  |     Meaning          |      Example     |
275 ///   -----------------------------------------------------
276 ///   |         |                      |  Input |  Output |
277 ///   =====================================================
278 ///   | P / p   | Percentage           |  0.05  |  5.00%  |
279 ///   | F / f   | Fixed point          |   1.0  |  1.00   |
280 ///   |   E     | Exponential with E   | 100000 | 1.0E+05 |
281 ///   |   e     | Exponential with e   | 100000 | 1.0e+05 |
282 ///   | (empty) | Same as F / f        |        |         |
283 ///   =====================================================
284 ///
285 /// The default precision is 6 for exponential (E / e) and 2 for everything
286 /// else.
287 
288 template <typename T>
289 struct format_provider<
290     T, typename std::enable_if<detail::use_double_formatter<T>::value>::type>
291     : public detail::HelperFunctions {
292   static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
293     FloatStyle S;
294     if (Style.consume_front("P") || Style.consume_front("p"))
295       S = FloatStyle::Percent;
296     else if (Style.consume_front("F") || Style.consume_front("f"))
297       S = FloatStyle::Fixed;
298     else if (Style.consume_front("E"))
299       S = FloatStyle::ExponentUpper;
300     else if (Style.consume_front("e"))
301       S = FloatStyle::Exponent;
302     else
303       S = FloatStyle::Fixed;
304 
305     Optional<size_t> Precision = parseNumericPrecision(Style);
306     if (!Precision.hasValue())
307       Precision = getDefaultPrecision(S);
308 
309     write_double(Stream, static_cast<double>(V), S, Precision);
310   }
311 };
312 
313 namespace detail {
314 template <typename IterT>
315 using IterValue = typename std::iterator_traits<IterT>::value_type;
316 
317 template <typename IterT>
318 struct range_item_has_provider
319     : public std::integral_constant<
320           bool, !uses_missing_provider<IterValue<IterT>>::value> {};
321 }
322 
323 /// Implementation of format_provider<T> for ranges.
324 ///
325 /// This will print an arbitrary range as a delimited sequence of items.
326 ///
327 /// The options string of a range type has the grammar:
328 ///
329 ///   range_style       ::= [separator] [element_style]
330 ///   separator         ::= "$" delimeted_expr
331 ///   element_style     ::= "@" delimeted_expr
332 ///   delimeted_expr    ::= "[" expr "]" | "(" expr ")" | "<" expr ">"
333 ///   expr              ::= <any string not containing delimeter>
334 ///
335 /// where the separator expression is the string to insert between consecutive
336 /// items in the range and the argument expression is the Style specification to
337 /// be used when formatting the underlying type.  The default separator if
338 /// unspecified is ' ' (space).  The syntax of the argument expression follows
339 /// whatever grammar is dictated by the format provider or format adapter used
340 /// to format the value type.
341 ///
342 /// Note that attempting to format an `iterator_range<T>` where no format
343 /// provider can be found for T will result in a compile error.
344 ///
345 
346 template <typename IterT> class format_provider<llvm::iterator_range<IterT>> {
347   using value = typename std::iterator_traits<IterT>::value_type;
348   using reference = typename std::iterator_traits<IterT>::reference;
349 
350   static StringRef consumeOneOption(StringRef &Style, char Indicator,
351                                     StringRef Default) {
352     if (Style.empty())
353       return Default;
354     if (Style.front() != Indicator)
355       return Default;
356     Style = Style.drop_front();
357     if (Style.empty()) {
358       assert(false && "Invalid range style");
359       return Default;
360     }
361 
362     std::vector<const char *> Delims = {"[]", "<>", "()"};
363     for (const char *D : Delims) {
364       if (Style.front() != D[0])
365         continue;
366       size_t End = Style.find_first_of(D[1]);
367       if (End == StringRef::npos) {
368         assert(false && "Missing range option end delimeter!");
369         return Default;
370       }
371       StringRef Result = Style.slice(1, End);
372       Style = Style.drop_front(End + 1);
373       return Result;
374     }
375     assert(false && "Invalid range style!");
376     return Default;
377   }
378 
379   static std::pair<StringRef, StringRef> parseOptions(StringRef Style) {
380     StringRef Sep = consumeOneOption(Style, '$', ", ");
381     StringRef Args = consumeOneOption(Style, '@', "");
382     assert(Style.empty() && "Unexpected text in range option string!");
383     return std::make_pair(Sep, Args);
384   }
385 
386 public:
387   static_assert(detail::range_item_has_provider<IterT>::value,
388                 "Range value_type does not have a format provider!");
389   static void format(const llvm::iterator_range<IterT> &V,
390                      llvm::raw_ostream &Stream, StringRef Style) {
391     StringRef Sep;
392     StringRef ArgStyle;
393     std::tie(Sep, ArgStyle) = parseOptions(Style);
394     auto Begin = V.begin();
395     auto End = V.end();
396     if (Begin != End) {
397       auto Adapter =
398           detail::build_format_adapter(std::forward<reference>(*Begin));
399       Adapter.format(Stream, ArgStyle);
400       ++Begin;
401     }
402     while (Begin != End) {
403       Stream << Sep;
404       auto Adapter =
405           detail::build_format_adapter(std::forward<reference>(*Begin));
406       Adapter.format(Stream, ArgStyle);
407       ++Begin;
408     }
409   }
410 };
411 }
412 
413 #endif
414