- //===- FormatProviders.h - Formatters for common LLVM types -----*- C++ -*-===// 
- // 
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 
- // See https://llvm.org/LICENSE.txt for license information. 
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 
- // 
- //===----------------------------------------------------------------------===// 
- // 
- // This file implements format providers for many common LLVM types, for example 
- // allowing precision and width specifiers for scalar and string types. 
- // 
- //===----------------------------------------------------------------------===// 
-   
- #ifndef LLVM_SUPPORT_FORMATPROVIDERS_H 
- #define LLVM_SUPPORT_FORMATPROVIDERS_H 
-   
- #include "llvm/ADT/STLExtras.h" 
- #include "llvm/ADT/StringSwitch.h" 
- #include "llvm/ADT/Twine.h" 
- #include "llvm/Support/FormatVariadicDetails.h" 
- #include "llvm/Support/NativeFormatting.h" 
-   
- #include <array> 
- #include <optional> 
- #include <type_traits> 
-   
- namespace llvm { 
- namespace detail { 
- template <typename T> 
- struct use_integral_formatter 
-     : public std::integral_constant< 
-           bool, is_one_of<T, uint8_t, int16_t, uint16_t, int32_t, uint32_t, 
-                           int64_t, uint64_t, int, unsigned, long, unsigned long, 
-                           long long, unsigned long long>::value> {}; 
-   
- template <typename T> 
- struct use_char_formatter 
-     : public std::integral_constant<bool, std::is_same<T, char>::value> {}; 
-   
- template <typename T> 
- struct is_cstring 
-     : public std::integral_constant<bool, 
-                                     is_one_of<T, char *, const char *>::value> { 
- }; 
-   
- template <typename T> 
- struct use_string_formatter 
-     : public std::integral_constant<bool, 
-                                     std::is_convertible<T, llvm::StringRef>::value> {}; 
-   
- template <typename T> 
- struct use_pointer_formatter 
-     : public std::integral_constant<bool, std::is_pointer<T>::value && 
-                                               !is_cstring<T>::value> {}; 
-   
- template <typename T> 
- struct use_double_formatter 
-     : public std::integral_constant<bool, std::is_floating_point<T>::value> {}; 
-   
- class HelperFunctions { 
- protected: 
-   static std::optional<size_t> parseNumericPrecision(StringRef Str) { 
-     size_t Prec; 
-     std::optional<size_t> Result; 
-     if (Str.empty()) 
-       Result = std::nullopt; 
-     else if (Str.getAsInteger(10, Prec)) { 
-       assert(false && "Invalid precision specifier"); 
-       Result = std::nullopt; 
-     } else { 
-       assert(Prec < 100 && "Precision out of range"); 
-       Result = std::min<size_t>(99u, Prec); 
-     } 
-     return Result; 
-   } 
-   
-   static bool consumeHexStyle(StringRef &Str, HexPrintStyle &Style) { 
-     if (!Str.startswith_insensitive("x")) 
-       return false; 
-   
-     if (Str.consume_front("x-")) 
-       Style = HexPrintStyle::Lower; 
-     else if (Str.consume_front("X-")) 
-       Style = HexPrintStyle::Upper; 
-     else if (Str.consume_front("x+") || Str.consume_front("x")) 
-       Style = HexPrintStyle::PrefixLower; 
-     else if (Str.consume_front("X+") || Str.consume_front("X")) 
-       Style = HexPrintStyle::PrefixUpper; 
-     return true; 
-   } 
-   
-   static size_t consumeNumHexDigits(StringRef &Str, HexPrintStyle Style, 
-                                     size_t Default) { 
-     Str.consumeInteger(10, Default); 
-     if (isPrefixedHexStyle(Style)) 
-       Default += 2; 
-     return Default; 
-   } 
- }; 
- } 
-   
- /// Implementation of format_provider<T> for integral arithmetic types. 
- /// 
- /// The options string of an integral type has the grammar: 
- /// 
- ///   integer_options   :: [style][digits] 
- ///   style             :: <see table below> 
- ///   digits            :: <non-negative integer> 0-99 
- /// 
- ///   ========================================================================== 
- ///   |  style  |     Meaning          |      Example     | Digits Meaning     | 
- ///   -------------------------------------------------------------------------- 
- ///   |         |                      |  Input |  Output |                    | 
- ///   ========================================================================== 
- ///   |   x-    | Hex no prefix, lower |   42   |    2a   | Minimum # digits   | 
- ///   |   X-    | Hex no prefix, upper |   42   |    2A   | Minimum # digits   | 
- ///   | x+ / x  | Hex + prefix, lower  |   42   |   0x2a  | Minimum # digits   | 
- ///   | X+ / X  | Hex + prefix, upper  |   42   |   0x2A  | Minimum # digits   | 
- ///   | N / n   | Digit grouped number | 123456 | 123,456 | Ignored            | 
- ///   | D / d   | Integer              | 100000 | 100000  | Ignored            | 
- ///   | (empty) | Same as D / d        |        |         |                    | 
- ///   ========================================================================== 
- /// 
-   
- template <typename T> 
- struct format_provider< 
-     T, std::enable_if_t<detail::use_integral_formatter<T>::value>> 
-     : public detail::HelperFunctions { 
- private: 
- public: 
-   static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) { 
-     HexPrintStyle HS; 
-     size_t Digits = 0; 
-     if (consumeHexStyle(Style, HS)) { 
-       Digits = consumeNumHexDigits(Style, HS, 0); 
-       write_hex(Stream, V, HS, Digits); 
-       return; 
-     } 
-   
-     IntegerStyle IS = IntegerStyle::Integer; 
-     if (Style.consume_front("N") || Style.consume_front("n")) 
-       IS = IntegerStyle::Number; 
-     else if (Style.consume_front("D") || Style.consume_front("d")) 
-       IS = IntegerStyle::Integer; 
-   
-     Style.consumeInteger(10, Digits); 
-     assert(Style.empty() && "Invalid integral format style!"); 
-     write_integer(Stream, V, Digits, IS); 
-   } 
- }; 
-   
- /// Implementation of format_provider<T> for integral pointer types. 
- /// 
- /// The options string of a pointer type has the grammar: 
- /// 
- ///   pointer_options   :: [style][precision] 
- ///   style             :: <see table below> 
- ///   digits            :: <non-negative integer> 0-sizeof(void*) 
- /// 
- ///   ========================================================================== 
- ///   |   S     |     Meaning          |                Example                | 
- ///   -------------------------------------------------------------------------- 
- ///   |         |                      |       Input       |      Output       | 
- ///   ========================================================================== 
- ///   |   x-    | Hex no prefix, lower |    0xDEADBEEF     |     deadbeef      | 
- ///   |   X-    | Hex no prefix, upper |    0xDEADBEEF     |     DEADBEEF      | 
- ///   | x+ / x  | Hex + prefix, lower  |    0xDEADBEEF     |    0xdeadbeef     | 
- ///   | X+ / X  | Hex + prefix, upper  |    0xDEADBEEF     |    0xDEADBEEF     | 
- ///   | (empty) | Same as X+ / X       |                   |                   | 
- ///   ========================================================================== 
- /// 
- /// The default precision is the number of nibbles in a machine word, and in all 
- /// cases indicates the minimum number of nibbles to print. 
- template <typename T> 
- struct format_provider< 
-     T, std::enable_if_t<detail::use_pointer_formatter<T>::value>> 
-     : public detail::HelperFunctions { 
- private: 
- public: 
-   static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) { 
-     HexPrintStyle HS = HexPrintStyle::PrefixUpper; 
-     consumeHexStyle(Style, HS); 
-     size_t Digits = consumeNumHexDigits(Style, HS, sizeof(void *) * 2); 
-     write_hex(Stream, reinterpret_cast<std::uintptr_t>(V), HS, Digits); 
-   } 
- }; 
-   
- /// Implementation of format_provider<T> for c-style strings and string 
- /// objects such as std::string and llvm::StringRef. 
- /// 
- /// The options string of a string type has the grammar: 
- /// 
- ///   string_options :: [length] 
- /// 
- /// where `length` is an optional integer specifying the maximum number of 
- /// characters in the string to print.  If `length` is omitted, the string is 
- /// printed up to the null terminator. 
-   
- template <typename T> 
- struct format_provider< 
-     T, std::enable_if_t<detail::use_string_formatter<T>::value>> { 
-   static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) { 
-     size_t N = StringRef::npos; 
-     if (!Style.empty() && Style.getAsInteger(10, N)) { 
-       assert(false && "Style is not a valid integer"); 
-     } 
-     llvm::StringRef S = V; 
-     Stream << S.substr(0, N); 
-   } 
- }; 
-   
- /// Implementation of format_provider<T> for llvm::Twine. 
- /// 
- /// This follows the same rules as the string formatter. 
-   
- template <> struct format_provider<Twine> { 
-   static void format(const Twine &V, llvm::raw_ostream &Stream, 
-                      StringRef Style) { 
-     format_provider<std::string>::format(V.str(), Stream, Style); 
-   } 
- }; 
-   
- /// Implementation of format_provider<T> for characters. 
- /// 
- /// The options string of a character type has the grammar: 
- /// 
- ///   char_options :: (empty) | [integer_options] 
- /// 
- /// If `char_options` is empty, the character is displayed as an ASCII 
- /// character.  Otherwise, it is treated as an integer options string. 
- /// 
- template <typename T> 
- struct format_provider<T, 
-                        std::enable_if_t<detail::use_char_formatter<T>::value>> { 
-   static void format(const char &V, llvm::raw_ostream &Stream, 
-                      StringRef Style) { 
-     if (Style.empty()) 
-       Stream << V; 
-     else { 
-       int X = static_cast<int>(V); 
-       format_provider<int>::format(X, Stream, Style); 
-     } 
-   } 
- }; 
-   
- /// Implementation of format_provider<T> for type `bool` 
- /// 
- /// The options string of a boolean type has the grammar: 
- /// 
- ///   bool_options :: "" | "Y" | "y" | "D" | "d" | "T" | "t" 
- /// 
- ///   ================================== 
- ///   |    C    |     Meaning          | 
- ///   ================================== 
- ///   |    Y    |       YES / NO       | 
- ///   |    y    |       yes / no       | 
- ///   |  D / d  |    Integer 0 or 1    | 
- ///   |    T    |     TRUE / FALSE     | 
- ///   |    t    |     true / false     | 
- ///   | (empty) |   Equivalent to 't'  | 
- ///   ================================== 
- template <> struct format_provider<bool> { 
-   static void format(const bool &B, llvm::raw_ostream &Stream, 
-                      StringRef Style) { 
-     Stream << StringSwitch<const char *>(Style) 
-                   .Case("Y", B ? "YES" : "NO") 
-                   .Case("y", B ? "yes" : "no") 
-                   .CaseLower("D", B ? "1" : "0") 
-                   .Case("T", B ? "TRUE" : "FALSE") 
-                   .Cases("t", "", B ? "true" : "false") 
-                   .Default(B ? "1" : "0"); 
-   } 
- }; 
-   
- /// Implementation of format_provider<T> for floating point types. 
- /// 
- /// The options string of a floating point type has the format: 
- /// 
- ///   float_options   :: [style][precision] 
- ///   style           :: <see table below> 
- ///   precision       :: <non-negative integer> 0-99 
- /// 
- ///   ===================================================== 
- ///   |  style  |     Meaning          |      Example     | 
- ///   ----------------------------------------------------- 
- ///   |         |                      |  Input |  Output | 
- ///   ===================================================== 
- ///   | P / p   | Percentage           |  0.05  |  5.00%  | 
- ///   | F / f   | Fixed point          |   1.0  |  1.00   | 
- ///   |   E     | Exponential with E   | 100000 | 1.0E+05 | 
- ///   |   e     | Exponential with e   | 100000 | 1.0e+05 | 
- ///   | (empty) | Same as F / f        |        |         | 
- ///   ===================================================== 
- /// 
- /// The default precision is 6 for exponential (E / e) and 2 for everything 
- /// else. 
-   
- template <typename T> 
- struct format_provider<T, 
-                        std::enable_if_t<detail::use_double_formatter<T>::value>> 
-     : public detail::HelperFunctions { 
-   static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) { 
-     FloatStyle S; 
-     if (Style.consume_front("P") || Style.consume_front("p")) 
-       S = FloatStyle::Percent; 
-     else if (Style.consume_front("F") || Style.consume_front("f")) 
-       S = FloatStyle::Fixed; 
-     else if (Style.consume_front("E")) 
-       S = FloatStyle::ExponentUpper; 
-     else if (Style.consume_front("e")) 
-       S = FloatStyle::Exponent; 
-     else 
-       S = FloatStyle::Fixed; 
-   
-     std::optional<size_t> Precision = parseNumericPrecision(Style); 
-     if (!Precision) 
-       Precision = getDefaultPrecision(S); 
-   
-     write_double(Stream, static_cast<double>(V), S, Precision); 
-   } 
- }; 
-   
- namespace detail { 
- template <typename IterT> 
- using IterValue = typename std::iterator_traits<IterT>::value_type; 
-   
- template <typename IterT> 
- struct range_item_has_provider 
-     : public std::integral_constant< 
-           bool, !uses_missing_provider<IterValue<IterT>>::value> {}; 
- } 
-   
- /// Implementation of format_provider<T> for ranges. 
- /// 
- /// This will print an arbitrary range as a delimited sequence of items. 
- /// 
- /// The options string of a range type has the grammar: 
- /// 
- ///   range_style       ::= [separator] [element_style] 
- ///   separator         ::= "$" delimeted_expr 
- ///   element_style     ::= "@" delimeted_expr 
- ///   delimeted_expr    ::= "[" expr "]" | "(" expr ")" | "<" expr ">" 
- ///   expr              ::= <any string not containing delimeter> 
- /// 
- /// where the separator expression is the string to insert between consecutive 
- /// items in the range and the argument expression is the Style specification to 
- /// be used when formatting the underlying type.  The default separator if 
- /// unspecified is ' ' (space).  The syntax of the argument expression follows 
- /// whatever grammar is dictated by the format provider or format adapter used 
- /// to format the value type. 
- /// 
- /// Note that attempting to format an `iterator_range<T>` where no format 
- /// provider can be found for T will result in a compile error. 
- /// 
-   
- template <typename IterT> class format_provider<llvm::iterator_range<IterT>> { 
-   using value = typename std::iterator_traits<IterT>::value_type; 
-   
-   static StringRef consumeOneOption(StringRef &Style, char Indicator, 
-                                     StringRef Default) { 
-     if (Style.empty()) 
-       return Default; 
-     if (Style.front() != Indicator) 
-       return Default; 
-     Style = Style.drop_front(); 
-     if (Style.empty()) { 
-       assert(false && "Invalid range style"); 
-       return Default; 
-     } 
-   
-     for (const char *D : std::array<const char *, 3>{"[]", "<>", "()"}) { 
-       if (Style.front() != D[0]) 
-         continue; 
-       size_t End = Style.find_first_of(D[1]); 
-       if (End == StringRef::npos) { 
-         assert(false && "Missing range option end delimeter!"); 
-         return Default; 
-       } 
-       StringRef Result = Style.slice(1, End); 
-       Style = Style.drop_front(End + 1); 
-       return Result; 
-     } 
-     assert(false && "Invalid range style!"); 
-     return Default; 
-   } 
-   
-   static std::pair<StringRef, StringRef> parseOptions(StringRef Style) { 
-     StringRef Sep = consumeOneOption(Style, '$', ", "); 
-     StringRef Args = consumeOneOption(Style, '@', ""); 
-     assert(Style.empty() && "Unexpected text in range option string!"); 
-     return std::make_pair(Sep, Args); 
-   } 
-   
- public: 
-   static_assert(detail::range_item_has_provider<IterT>::value, 
-                 "Range value_type does not have a format provider!"); 
-   static void format(const llvm::iterator_range<IterT> &V, 
-                      llvm::raw_ostream &Stream, StringRef Style) { 
-     StringRef Sep; 
-     StringRef ArgStyle; 
-     std::tie(Sep, ArgStyle) = parseOptions(Style); 
-     auto Begin = V.begin(); 
-     auto End = V.end(); 
-     if (Begin != End) { 
-       auto Adapter = detail::build_format_adapter(*Begin); 
-       Adapter.format(Stream, ArgStyle); 
-       ++Begin; 
-     } 
-     while (Begin != End) { 
-       Stream << Sep; 
-       auto Adapter = detail::build_format_adapter(*Begin); 
-       Adapter.format(Stream, ArgStyle); 
-       ++Begin; 
-     } 
-   } 
- }; 
- } 
-   
- #endif 
-