Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:44:30

0001 //===- FormatProviders.h - Formatters for common LLVM types -----*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // This file implements format providers for many common LLVM types, for example
0010 // allowing precision and width specifiers for scalar and string types.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_SUPPORT_FORMATPROVIDERS_H
0015 #define LLVM_SUPPORT_FORMATPROVIDERS_H
0016 
0017 #include "llvm/ADT/STLExtras.h"
0018 #include "llvm/ADT/StringSwitch.h"
0019 #include "llvm/ADT/Twine.h"
0020 #include "llvm/Support/FormatVariadicDetails.h"
0021 #include "llvm/Support/NativeFormatting.h"
0022 
0023 #include <array>
0024 #include <optional>
0025 #include <type_traits>
0026 
0027 namespace llvm {
0028 namespace support {
0029 namespace detail {
0030 template <typename T>
0031 struct use_integral_formatter
0032     : public std::integral_constant<
0033           bool, is_one_of<T, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
0034                           int64_t, uint64_t, int, unsigned, long, unsigned long,
0035                           long long, unsigned long long>::value> {};
0036 
0037 template <typename T>
0038 struct use_char_formatter
0039     : public std::integral_constant<bool, std::is_same_v<T, char>> {};
0040 
0041 template <typename T>
0042 struct is_cstring
0043     : public std::integral_constant<bool,
0044                                     is_one_of<T, char *, const char *>::value> {
0045 };
0046 
0047 template <typename T>
0048 struct use_string_formatter
0049     : public std::integral_constant<bool,
0050                                     std::is_convertible_v<T, llvm::StringRef>> {
0051 };
0052 
0053 template <typename T>
0054 struct use_pointer_formatter
0055     : public std::integral_constant<bool, std::is_pointer_v<T> &&
0056                                               !is_cstring<T>::value> {};
0057 
0058 template <typename T>
0059 struct use_double_formatter
0060     : public std::integral_constant<bool, std::is_floating_point_v<T>> {};
0061 
0062 class HelperFunctions {
0063 protected:
0064   static std::optional<size_t> parseNumericPrecision(StringRef Str) {
0065     size_t Prec;
0066     std::optional<size_t> Result;
0067     if (Str.empty())
0068       Result = std::nullopt;
0069     else if (Str.getAsInteger(10, Prec)) {
0070       assert(false && "Invalid precision specifier");
0071       Result = std::nullopt;
0072     } else {
0073       assert(Prec < 100 && "Precision out of range");
0074       Result = std::min<size_t>(99u, Prec);
0075     }
0076     return Result;
0077   }
0078 
0079   static std::optional<HexPrintStyle> consumeHexStyle(StringRef &Str) {
0080     if (!Str.starts_with_insensitive("x"))
0081       return std::nullopt;
0082 
0083     if (Str.consume_front("x-"))
0084       return HexPrintStyle::Lower;
0085     if (Str.consume_front("X-"))
0086       return HexPrintStyle::Upper;
0087     if (Str.consume_front("x+") || Str.consume_front("x"))
0088       return HexPrintStyle::PrefixLower;
0089     if (!Str.consume_front("X+"))
0090       Str.consume_front("X");
0091     return HexPrintStyle::PrefixUpper;
0092   }
0093 
0094   static size_t consumeNumHexDigits(StringRef &Str, HexPrintStyle Style,
0095                                     size_t Default) {
0096     Str.consumeInteger(10, Default);
0097     if (isPrefixedHexStyle(Style))
0098       Default += 2;
0099     return Default;
0100   }
0101 };
0102 } // namespace detail
0103 } // namespace support
0104 
0105 /// Implementation of format_provider<T> for integral arithmetic types.
0106 ///
0107 /// The options string of an integral type has the grammar:
0108 ///
0109 ///   integer_options   :: [style][digits]
0110 ///   style             :: <see table below>
0111 ///   digits            :: <non-negative integer> 0-99
0112 ///
0113 ///   ==========================================================================
0114 ///   |  style  |     Meaning          |      Example     | Digits Meaning     |
0115 ///   --------------------------------------------------------------------------
0116 ///   |         |                      |  Input |  Output |                    |
0117 ///   ==========================================================================
0118 ///   |   x-    | Hex no prefix, lower |   42   |    2a   | Minimum # digits   |
0119 ///   |   X-    | Hex no prefix, upper |   42   |    2A   | Minimum # digits   |
0120 ///   | x+ / x  | Hex + prefix, lower  |   42   |   0x2a  | Minimum # digits   |
0121 ///   | X+ / X  | Hex + prefix, upper  |   42   |   0x2A  | Minimum # digits   |
0122 ///   | N / n   | Digit grouped number | 123456 | 123,456 | Ignored            |
0123 ///   | D / d   | Integer              | 100000 | 100000  | Ignored            |
0124 ///   | (empty) | Same as D / d        |        |         |                    |
0125 ///   ==========================================================================
0126 ///
0127 
0128 template <typename T>
0129 struct format_provider<
0130     T, std::enable_if_t<support::detail::use_integral_formatter<T>::value>>
0131     : public support::detail::HelperFunctions {
0132 private:
0133 public:
0134   static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
0135     size_t Digits = 0;
0136     if (std::optional<HexPrintStyle> HS = consumeHexStyle(Style)) {
0137       Digits = consumeNumHexDigits(Style, *HS, 0);
0138       write_hex(Stream, V, *HS, Digits);
0139       return;
0140     }
0141 
0142     IntegerStyle IS = IntegerStyle::Integer;
0143     if (Style.consume_front("N") || Style.consume_front("n"))
0144       IS = IntegerStyle::Number;
0145     else if (Style.consume_front("D") || Style.consume_front("d"))
0146       IS = IntegerStyle::Integer;
0147 
0148     Style.consumeInteger(10, Digits);
0149     assert(Style.empty() && "Invalid integral format style!");
0150     write_integer(Stream, V, Digits, IS);
0151   }
0152 };
0153 
0154 /// Implementation of format_provider<T> for integral pointer types.
0155 ///
0156 /// The options string of a pointer type has the grammar:
0157 ///
0158 ///   pointer_options   :: [style][precision]
0159 ///   style             :: <see table below>
0160 ///   digits            :: <non-negative integer> 0-sizeof(void*)
0161 ///
0162 ///   ==========================================================================
0163 ///   |   S     |     Meaning          |                Example                |
0164 ///   --------------------------------------------------------------------------
0165 ///   |         |                      |       Input       |      Output       |
0166 ///   ==========================================================================
0167 ///   |   x-    | Hex no prefix, lower |    0xDEADBEEF     |     deadbeef      |
0168 ///   |   X-    | Hex no prefix, upper |    0xDEADBEEF     |     DEADBEEF      |
0169 ///   | x+ / x  | Hex + prefix, lower  |    0xDEADBEEF     |    0xdeadbeef     |
0170 ///   | X+ / X  | Hex + prefix, upper  |    0xDEADBEEF     |    0xDEADBEEF     |
0171 ///   | (empty) | Same as X+ / X       |                   |                   |
0172 ///   ==========================================================================
0173 ///
0174 /// The default precision is the number of nibbles in a machine word, and in all
0175 /// cases indicates the minimum number of nibbles to print.
0176 template <typename T>
0177 struct format_provider<
0178     T, std::enable_if_t<support::detail::use_pointer_formatter<T>::value>>
0179     : public support::detail::HelperFunctions {
0180 private:
0181 public:
0182   static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
0183     HexPrintStyle HS = HexPrintStyle::PrefixUpper;
0184     if (std::optional<HexPrintStyle> consumed = consumeHexStyle(Style))
0185       HS = *consumed;
0186     size_t Digits = consumeNumHexDigits(Style, HS, sizeof(void *) * 2);
0187     write_hex(Stream, reinterpret_cast<std::uintptr_t>(V), HS, Digits);
0188   }
0189 };
0190 
0191 /// Implementation of format_provider<T> for c-style strings and string
0192 /// objects such as std::string and llvm::StringRef.
0193 ///
0194 /// The options string of a string type has the grammar:
0195 ///
0196 ///   string_options :: [length]
0197 ///
0198 /// where `length` is an optional integer specifying the maximum number of
0199 /// characters in the string to print.  If `length` is omitted, the string is
0200 /// printed up to the null terminator.
0201 
0202 template <typename T>
0203 struct format_provider<
0204     T, std::enable_if_t<support::detail::use_string_formatter<T>::value>> {
0205   static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
0206     size_t N = StringRef::npos;
0207     if (!Style.empty() && Style.getAsInteger(10, N)) {
0208       assert(false && "Style is not a valid integer");
0209     }
0210     llvm::StringRef S = V;
0211     Stream << S.substr(0, N);
0212   }
0213 };
0214 
0215 /// Implementation of format_provider<T> for llvm::Twine.
0216 ///
0217 /// This follows the same rules as the string formatter.
0218 
0219 template <> struct format_provider<Twine> {
0220   static void format(const Twine &V, llvm::raw_ostream &Stream,
0221                      StringRef Style) {
0222     format_provider<std::string>::format(V.str(), Stream, Style);
0223   }
0224 };
0225 
0226 /// Implementation of format_provider<T> for characters.
0227 ///
0228 /// The options string of a character type has the grammar:
0229 ///
0230 ///   char_options :: (empty) | [integer_options]
0231 ///
0232 /// If `char_options` is empty, the character is displayed as an ASCII
0233 /// character.  Otherwise, it is treated as an integer options string.
0234 ///
0235 template <typename T>
0236 struct format_provider<
0237     T, std::enable_if_t<support::detail::use_char_formatter<T>::value>> {
0238   static void format(const char &V, llvm::raw_ostream &Stream,
0239                      StringRef Style) {
0240     if (Style.empty())
0241       Stream << V;
0242     else {
0243       int X = static_cast<int>(V);
0244       format_provider<int>::format(X, Stream, Style);
0245     }
0246   }
0247 };
0248 
0249 /// Implementation of format_provider<T> for type `bool`
0250 ///
0251 /// The options string of a boolean type has the grammar:
0252 ///
0253 ///   bool_options :: "" | "Y" | "y" | "D" | "d" | "T" | "t"
0254 ///
0255 ///   ==================================
0256 ///   |    C    |     Meaning          |
0257 ///   ==================================
0258 ///   |    Y    |       YES / NO       |
0259 ///   |    y    |       yes / no       |
0260 ///   |  D / d  |    Integer 0 or 1    |
0261 ///   |    T    |     TRUE / FALSE     |
0262 ///   |    t    |     true / false     |
0263 ///   | (empty) |   Equivalent to 't'  |
0264 ///   ==================================
0265 template <> struct format_provider<bool> {
0266   static void format(const bool &B, llvm::raw_ostream &Stream,
0267                      StringRef Style) {
0268     Stream << StringSwitch<const char *>(Style)
0269                   .Case("Y", B ? "YES" : "NO")
0270                   .Case("y", B ? "yes" : "no")
0271                   .CaseLower("D", B ? "1" : "0")
0272                   .Case("T", B ? "TRUE" : "FALSE")
0273                   .Cases("t", "", B ? "true" : "false")
0274                   .Default(B ? "1" : "0");
0275   }
0276 };
0277 
0278 /// Implementation of format_provider<T> for floating point types.
0279 ///
0280 /// The options string of a floating point type has the format:
0281 ///
0282 ///   float_options   :: [style][precision]
0283 ///   style           :: <see table below>
0284 ///   precision       :: <non-negative integer> 0-99
0285 ///
0286 ///   =====================================================
0287 ///   |  style  |     Meaning          |      Example     |
0288 ///   -----------------------------------------------------
0289 ///   |         |                      |  Input |  Output |
0290 ///   =====================================================
0291 ///   | P / p   | Percentage           |  0.05  |  5.00%  |
0292 ///   | F / f   | Fixed point          |   1.0  |  1.00   |
0293 ///   |   E     | Exponential with E   | 100000 | 1.0E+05 |
0294 ///   |   e     | Exponential with e   | 100000 | 1.0e+05 |
0295 ///   | (empty) | Same as F / f        |        |         |
0296 ///   =====================================================
0297 ///
0298 /// The default precision is 6 for exponential (E / e) and 2 for everything
0299 /// else.
0300 
0301 template <typename T>
0302 struct format_provider<
0303     T, std::enable_if_t<support::detail::use_double_formatter<T>::value>>
0304     : public support::detail::HelperFunctions {
0305   static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
0306     FloatStyle S;
0307     if (Style.consume_front("P") || Style.consume_front("p"))
0308       S = FloatStyle::Percent;
0309     else if (Style.consume_front("F") || Style.consume_front("f"))
0310       S = FloatStyle::Fixed;
0311     else if (Style.consume_front("E"))
0312       S = FloatStyle::ExponentUpper;
0313     else if (Style.consume_front("e"))
0314       S = FloatStyle::Exponent;
0315     else
0316       S = FloatStyle::Fixed;
0317 
0318     std::optional<size_t> Precision = parseNumericPrecision(Style);
0319     if (!Precision)
0320       Precision = getDefaultPrecision(S);
0321 
0322     write_double(Stream, static_cast<double>(V), S, Precision);
0323   }
0324 };
0325 
0326 namespace support {
0327 namespace detail {
0328 template <typename IterT>
0329 using IterValue = typename std::iterator_traits<IterT>::value_type;
0330 
0331 template <typename IterT>
0332 struct range_item_has_provider
0333     : public std::integral_constant<
0334           bool,
0335           !support::detail::uses_missing_provider<IterValue<IterT>>::value> {};
0336 } // namespace detail
0337 } // namespace support
0338 
0339 /// Implementation of format_provider<T> for ranges.
0340 ///
0341 /// This will print an arbitrary range as a delimited sequence of items.
0342 ///
0343 /// The options string of a range type has the grammar:
0344 ///
0345 ///   range_style       ::= [separator] [element_style]
0346 ///   separator         ::= "$" delimeted_expr
0347 ///   element_style     ::= "@" delimeted_expr
0348 ///   delimeted_expr    ::= "[" expr "]" | "(" expr ")" | "<" expr ">"
0349 ///   expr              ::= <any string not containing delimeter>
0350 ///
0351 /// where the separator expression is the string to insert between consecutive
0352 /// items in the range and the argument expression is the Style specification to
0353 /// be used when formatting the underlying type.  The default separator if
0354 /// unspecified is ' ' (space).  The syntax of the argument expression follows
0355 /// whatever grammar is dictated by the format provider or format adapter used
0356 /// to format the value type.
0357 ///
0358 /// Note that attempting to format an `iterator_range<T>` where no format
0359 /// provider can be found for T will result in a compile error.
0360 ///
0361 
0362 template <typename IterT> class format_provider<llvm::iterator_range<IterT>> {
0363   using value = typename std::iterator_traits<IterT>::value_type;
0364 
0365   static StringRef consumeOneOption(StringRef &Style, char Indicator,
0366                                     StringRef Default) {
0367     if (Style.empty())
0368       return Default;
0369     if (Style.front() != Indicator)
0370       return Default;
0371     Style = Style.drop_front();
0372     if (Style.empty()) {
0373       assert(false && "Invalid range style");
0374       return Default;
0375     }
0376 
0377     for (const char *D : std::array<const char *, 3>{"[]", "<>", "()"}) {
0378       if (Style.front() != D[0])
0379         continue;
0380       size_t End = Style.find_first_of(D[1]);
0381       if (End == StringRef::npos) {
0382         assert(false && "Missing range option end delimeter!");
0383         return Default;
0384       }
0385       StringRef Result = Style.slice(1, End);
0386       Style = Style.drop_front(End + 1);
0387       return Result;
0388     }
0389     assert(false && "Invalid range style!");
0390     return Default;
0391   }
0392 
0393   static std::pair<StringRef, StringRef> parseOptions(StringRef Style) {
0394     StringRef Sep = consumeOneOption(Style, '$', ", ");
0395     StringRef Args = consumeOneOption(Style, '@', "");
0396     assert(Style.empty() && "Unexpected text in range option string!");
0397     return std::make_pair(Sep, Args);
0398   }
0399 
0400 public:
0401   static_assert(support::detail::range_item_has_provider<IterT>::value,
0402                 "Range value_type does not have a format provider!");
0403   static void format(const llvm::iterator_range<IterT> &V,
0404                      llvm::raw_ostream &Stream, StringRef Style) {
0405     StringRef Sep;
0406     StringRef ArgStyle;
0407     std::tie(Sep, ArgStyle) = parseOptions(Style);
0408     auto Begin = V.begin();
0409     auto End = V.end();
0410     if (Begin != End) {
0411       auto Adapter = support::detail::build_format_adapter(*Begin);
0412       Adapter.format(Stream, ArgStyle);
0413       ++Begin;
0414     }
0415     while (Begin != End) {
0416       Stream << Sep;
0417       auto Adapter = support::detail::build_format_adapter(*Begin);
0418       Adapter.format(Stream, ArgStyle);
0419       ++Begin;
0420     }
0421   }
0422 };
0423 } // namespace llvm
0424 
0425 #endif