Home | History | Annotate | Download | only in Support
      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:
     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 
     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 
     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