10b57cec5SDimitry Andric //===- FormatProviders.h - Formatters for common LLVM types -----*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements format providers for many common LLVM types, for example 100b57cec5SDimitry Andric // allowing precision and width specifiers for scalar and string types. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #ifndef LLVM_SUPPORT_FORMATPROVIDERS_H 150b57cec5SDimitry Andric #define LLVM_SUPPORT_FORMATPROVIDERS_H 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 180b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h" 190b57cec5SDimitry Andric #include "llvm/ADT/Twine.h" 200b57cec5SDimitry Andric #include "llvm/Support/FormatVariadicDetails.h" 210b57cec5SDimitry Andric #include "llvm/Support/NativeFormatting.h" 220b57cec5SDimitry Andric 23bdd1243dSDimitry Andric #include <array> 24bdd1243dSDimitry Andric #include <optional> 250b57cec5SDimitry Andric #include <type_traits> 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric namespace llvm { 28*0fca6ea1SDimitry Andric namespace support { 290b57cec5SDimitry Andric namespace detail { 300b57cec5SDimitry Andric template <typename T> 310b57cec5SDimitry Andric struct use_integral_formatter 320b57cec5SDimitry Andric : public std::integral_constant< 330b57cec5SDimitry Andric bool, is_one_of<T, uint8_t, int16_t, uint16_t, int32_t, uint32_t, 340b57cec5SDimitry Andric int64_t, uint64_t, int, unsigned, long, unsigned long, 350b57cec5SDimitry Andric long long, unsigned long long>::value> {}; 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric template <typename T> 380b57cec5SDimitry Andric struct use_char_formatter 3906c3fb27SDimitry Andric : public std::integral_constant<bool, std::is_same_v<T, char>> {}; 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric template <typename T> 420b57cec5SDimitry Andric struct is_cstring 430b57cec5SDimitry Andric : public std::integral_constant<bool, 440b57cec5SDimitry Andric is_one_of<T, char *, const char *>::value> { 450b57cec5SDimitry Andric }; 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric template <typename T> 480b57cec5SDimitry Andric struct use_string_formatter 490b57cec5SDimitry Andric : public std::integral_constant<bool, 5006c3fb27SDimitry Andric std::is_convertible_v<T, llvm::StringRef>> { 5106c3fb27SDimitry Andric }; 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric template <typename T> 540b57cec5SDimitry Andric struct use_pointer_formatter 5506c3fb27SDimitry Andric : public std::integral_constant<bool, std::is_pointer_v<T> && 560b57cec5SDimitry Andric !is_cstring<T>::value> {}; 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric template <typename T> 590b57cec5SDimitry Andric struct use_double_formatter 6006c3fb27SDimitry Andric : public std::integral_constant<bool, std::is_floating_point_v<T>> {}; 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric class HelperFunctions { 630b57cec5SDimitry Andric protected: 64bdd1243dSDimitry Andric static std::optional<size_t> parseNumericPrecision(StringRef Str) { 650b57cec5SDimitry Andric size_t Prec; 66bdd1243dSDimitry Andric std::optional<size_t> Result; 670b57cec5SDimitry Andric if (Str.empty()) 68bdd1243dSDimitry Andric Result = std::nullopt; 690b57cec5SDimitry Andric else if (Str.getAsInteger(10, Prec)) { 700b57cec5SDimitry Andric assert(false && "Invalid precision specifier"); 71bdd1243dSDimitry Andric Result = std::nullopt; 720b57cec5SDimitry Andric } else { 730b57cec5SDimitry Andric assert(Prec < 100 && "Precision out of range"); 740b57cec5SDimitry Andric Result = std::min<size_t>(99u, Prec); 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric return Result; 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric 79*0fca6ea1SDimitry Andric static std::optional<HexPrintStyle> consumeHexStyle(StringRef &Str) { 8006c3fb27SDimitry Andric if (!Str.starts_with_insensitive("x")) 81*0fca6ea1SDimitry Andric return std::nullopt; 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric if (Str.consume_front("x-")) 84*0fca6ea1SDimitry Andric return HexPrintStyle::Lower; 85*0fca6ea1SDimitry Andric if (Str.consume_front("X-")) 86*0fca6ea1SDimitry Andric return HexPrintStyle::Upper; 87*0fca6ea1SDimitry Andric if (Str.consume_front("x+") || Str.consume_front("x")) 88*0fca6ea1SDimitry Andric return HexPrintStyle::PrefixLower; 89*0fca6ea1SDimitry Andric if (!Str.consume_front("X+")) 90*0fca6ea1SDimitry Andric Str.consume_front("X"); 91*0fca6ea1SDimitry Andric return HexPrintStyle::PrefixUpper; 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric static size_t consumeNumHexDigits(StringRef &Str, HexPrintStyle Style, 950b57cec5SDimitry Andric size_t Default) { 960b57cec5SDimitry Andric Str.consumeInteger(10, Default); 970b57cec5SDimitry Andric if (isPrefixedHexStyle(Style)) 980b57cec5SDimitry Andric Default += 2; 990b57cec5SDimitry Andric return Default; 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric }; 102*0fca6ea1SDimitry Andric } // namespace detail 103*0fca6ea1SDimitry Andric } // namespace support 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric /// Implementation of format_provider<T> for integral arithmetic types. 1060b57cec5SDimitry Andric /// 1070b57cec5SDimitry Andric /// The options string of an integral type has the grammar: 1080b57cec5SDimitry Andric /// 1090b57cec5SDimitry Andric /// integer_options :: [style][digits] 1100b57cec5SDimitry Andric /// style :: <see table below> 1110b57cec5SDimitry Andric /// digits :: <non-negative integer> 0-99 1120b57cec5SDimitry Andric /// 1130b57cec5SDimitry Andric /// ========================================================================== 1140b57cec5SDimitry Andric /// | style | Meaning | Example | Digits Meaning | 1150b57cec5SDimitry Andric /// -------------------------------------------------------------------------- 1160b57cec5SDimitry Andric /// | | | Input | Output | | 1170b57cec5SDimitry Andric /// ========================================================================== 1180b57cec5SDimitry Andric /// | x- | Hex no prefix, lower | 42 | 2a | Minimum # digits | 1190b57cec5SDimitry Andric /// | X- | Hex no prefix, upper | 42 | 2A | Minimum # digits | 1200b57cec5SDimitry Andric /// | x+ / x | Hex + prefix, lower | 42 | 0x2a | Minimum # digits | 1210b57cec5SDimitry Andric /// | X+ / X | Hex + prefix, upper | 42 | 0x2A | Minimum # digits | 1220b57cec5SDimitry Andric /// | N / n | Digit grouped number | 123456 | 123,456 | Ignored | 1230b57cec5SDimitry Andric /// | D / d | Integer | 100000 | 100000 | Ignored | 1240b57cec5SDimitry Andric /// | (empty) | Same as D / d | | | | 1250b57cec5SDimitry Andric /// ========================================================================== 1260b57cec5SDimitry Andric /// 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric template <typename T> 1290b57cec5SDimitry Andric struct format_provider< 130*0fca6ea1SDimitry Andric T, std::enable_if_t<support::detail::use_integral_formatter<T>::value>> 131*0fca6ea1SDimitry Andric : public support::detail::HelperFunctions { 1320b57cec5SDimitry Andric private: 1330b57cec5SDimitry Andric public: 1340b57cec5SDimitry Andric static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) { 1350b57cec5SDimitry Andric size_t Digits = 0; 136*0fca6ea1SDimitry Andric if (std::optional<HexPrintStyle> HS = consumeHexStyle(Style)) { 137*0fca6ea1SDimitry Andric Digits = consumeNumHexDigits(Style, *HS, 0); 138*0fca6ea1SDimitry Andric write_hex(Stream, V, *HS, Digits); 1390b57cec5SDimitry Andric return; 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric IntegerStyle IS = IntegerStyle::Integer; 1430b57cec5SDimitry Andric if (Style.consume_front("N") || Style.consume_front("n")) 1440b57cec5SDimitry Andric IS = IntegerStyle::Number; 1450b57cec5SDimitry Andric else if (Style.consume_front("D") || Style.consume_front("d")) 1460b57cec5SDimitry Andric IS = IntegerStyle::Integer; 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric Style.consumeInteger(10, Digits); 1490b57cec5SDimitry Andric assert(Style.empty() && "Invalid integral format style!"); 1500b57cec5SDimitry Andric write_integer(Stream, V, Digits, IS); 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric }; 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric /// Implementation of format_provider<T> for integral pointer types. 1550b57cec5SDimitry Andric /// 1560b57cec5SDimitry Andric /// The options string of a pointer type has the grammar: 1570b57cec5SDimitry Andric /// 1580b57cec5SDimitry Andric /// pointer_options :: [style][precision] 1590b57cec5SDimitry Andric /// style :: <see table below> 1600b57cec5SDimitry Andric /// digits :: <non-negative integer> 0-sizeof(void*) 1610b57cec5SDimitry Andric /// 1620b57cec5SDimitry Andric /// ========================================================================== 1630b57cec5SDimitry Andric /// | S | Meaning | Example | 1640b57cec5SDimitry Andric /// -------------------------------------------------------------------------- 1650b57cec5SDimitry Andric /// | | | Input | Output | 1660b57cec5SDimitry Andric /// ========================================================================== 1670b57cec5SDimitry Andric /// | x- | Hex no prefix, lower | 0xDEADBEEF | deadbeef | 1680b57cec5SDimitry Andric /// | X- | Hex no prefix, upper | 0xDEADBEEF | DEADBEEF | 1690b57cec5SDimitry Andric /// | x+ / x | Hex + prefix, lower | 0xDEADBEEF | 0xdeadbeef | 1700b57cec5SDimitry Andric /// | X+ / X | Hex + prefix, upper | 0xDEADBEEF | 0xDEADBEEF | 1710b57cec5SDimitry Andric /// | (empty) | Same as X+ / X | | | 1720b57cec5SDimitry Andric /// ========================================================================== 1730b57cec5SDimitry Andric /// 1740b57cec5SDimitry Andric /// The default precision is the number of nibbles in a machine word, and in all 1750b57cec5SDimitry Andric /// cases indicates the minimum number of nibbles to print. 1760b57cec5SDimitry Andric template <typename T> 1770b57cec5SDimitry Andric struct format_provider< 178*0fca6ea1SDimitry Andric T, std::enable_if_t<support::detail::use_pointer_formatter<T>::value>> 179*0fca6ea1SDimitry Andric : public support::detail::HelperFunctions { 1800b57cec5SDimitry Andric private: 1810b57cec5SDimitry Andric public: 1820b57cec5SDimitry Andric static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) { 1830b57cec5SDimitry Andric HexPrintStyle HS = HexPrintStyle::PrefixUpper; 184*0fca6ea1SDimitry Andric if (std::optional<HexPrintStyle> consumed = consumeHexStyle(Style)) 185*0fca6ea1SDimitry Andric HS = *consumed; 1860b57cec5SDimitry Andric size_t Digits = consumeNumHexDigits(Style, HS, sizeof(void *) * 2); 1870b57cec5SDimitry Andric write_hex(Stream, reinterpret_cast<std::uintptr_t>(V), HS, Digits); 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric }; 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric /// Implementation of format_provider<T> for c-style strings and string 1920b57cec5SDimitry Andric /// objects such as std::string and llvm::StringRef. 1930b57cec5SDimitry Andric /// 1940b57cec5SDimitry Andric /// The options string of a string type has the grammar: 1950b57cec5SDimitry Andric /// 1960b57cec5SDimitry Andric /// string_options :: [length] 1970b57cec5SDimitry Andric /// 1980b57cec5SDimitry Andric /// where `length` is an optional integer specifying the maximum number of 1990b57cec5SDimitry Andric /// characters in the string to print. If `length` is omitted, the string is 2000b57cec5SDimitry Andric /// printed up to the null terminator. 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric template <typename T> 2030b57cec5SDimitry Andric struct format_provider< 204*0fca6ea1SDimitry Andric T, std::enable_if_t<support::detail::use_string_formatter<T>::value>> { 2050b57cec5SDimitry Andric static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) { 2060b57cec5SDimitry Andric size_t N = StringRef::npos; 2070b57cec5SDimitry Andric if (!Style.empty() && Style.getAsInteger(10, N)) { 2080b57cec5SDimitry Andric assert(false && "Style is not a valid integer"); 2090b57cec5SDimitry Andric } 2100b57cec5SDimitry Andric llvm::StringRef S = V; 2110b57cec5SDimitry Andric Stream << S.substr(0, N); 2120b57cec5SDimitry Andric } 2130b57cec5SDimitry Andric }; 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric /// Implementation of format_provider<T> for llvm::Twine. 2160b57cec5SDimitry Andric /// 2170b57cec5SDimitry Andric /// This follows the same rules as the string formatter. 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric template <> struct format_provider<Twine> { 2200b57cec5SDimitry Andric static void format(const Twine &V, llvm::raw_ostream &Stream, 2210b57cec5SDimitry Andric StringRef Style) { 2220b57cec5SDimitry Andric format_provider<std::string>::format(V.str(), Stream, Style); 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric }; 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric /// Implementation of format_provider<T> for characters. 2270b57cec5SDimitry Andric /// 2280b57cec5SDimitry Andric /// The options string of a character type has the grammar: 2290b57cec5SDimitry Andric /// 2300b57cec5SDimitry Andric /// char_options :: (empty) | [integer_options] 2310b57cec5SDimitry Andric /// 2320b57cec5SDimitry Andric /// If `char_options` is empty, the character is displayed as an ASCII 2330b57cec5SDimitry Andric /// character. Otherwise, it is treated as an integer options string. 2340b57cec5SDimitry Andric /// 2350b57cec5SDimitry Andric template <typename T> 236*0fca6ea1SDimitry Andric struct format_provider< 237*0fca6ea1SDimitry Andric T, std::enable_if_t<support::detail::use_char_formatter<T>::value>> { 2380b57cec5SDimitry Andric static void format(const char &V, llvm::raw_ostream &Stream, 2390b57cec5SDimitry Andric StringRef Style) { 2400b57cec5SDimitry Andric if (Style.empty()) 2410b57cec5SDimitry Andric Stream << V; 2420b57cec5SDimitry Andric else { 2430b57cec5SDimitry Andric int X = static_cast<int>(V); 2440b57cec5SDimitry Andric format_provider<int>::format(X, Stream, Style); 2450b57cec5SDimitry Andric } 2460b57cec5SDimitry Andric } 2470b57cec5SDimitry Andric }; 2480b57cec5SDimitry Andric 2490b57cec5SDimitry Andric /// Implementation of format_provider<T> for type `bool` 2500b57cec5SDimitry Andric /// 2510b57cec5SDimitry Andric /// The options string of a boolean type has the grammar: 2520b57cec5SDimitry Andric /// 2530b57cec5SDimitry Andric /// bool_options :: "" | "Y" | "y" | "D" | "d" | "T" | "t" 2540b57cec5SDimitry Andric /// 2550b57cec5SDimitry Andric /// ================================== 2560b57cec5SDimitry Andric /// | C | Meaning | 2570b57cec5SDimitry Andric /// ================================== 2580b57cec5SDimitry Andric /// | Y | YES / NO | 2590b57cec5SDimitry Andric /// | y | yes / no | 2600b57cec5SDimitry Andric /// | D / d | Integer 0 or 1 | 2610b57cec5SDimitry Andric /// | T | TRUE / FALSE | 2620b57cec5SDimitry Andric /// | t | true / false | 2630b57cec5SDimitry Andric /// | (empty) | Equivalent to 't' | 2640b57cec5SDimitry Andric /// ================================== 2650b57cec5SDimitry Andric template <> struct format_provider<bool> { 2660b57cec5SDimitry Andric static void format(const bool &B, llvm::raw_ostream &Stream, 2670b57cec5SDimitry Andric StringRef Style) { 2680b57cec5SDimitry Andric Stream << StringSwitch<const char *>(Style) 2690b57cec5SDimitry Andric .Case("Y", B ? "YES" : "NO") 2700b57cec5SDimitry Andric .Case("y", B ? "yes" : "no") 2710b57cec5SDimitry Andric .CaseLower("D", B ? "1" : "0") 2720b57cec5SDimitry Andric .Case("T", B ? "TRUE" : "FALSE") 2730b57cec5SDimitry Andric .Cases("t", "", B ? "true" : "false") 2740b57cec5SDimitry Andric .Default(B ? "1" : "0"); 2750b57cec5SDimitry Andric } 2760b57cec5SDimitry Andric }; 2770b57cec5SDimitry Andric 2780b57cec5SDimitry Andric /// Implementation of format_provider<T> for floating point types. 2790b57cec5SDimitry Andric /// 2800b57cec5SDimitry Andric /// The options string of a floating point type has the format: 2810b57cec5SDimitry Andric /// 2820b57cec5SDimitry Andric /// float_options :: [style][precision] 2830b57cec5SDimitry Andric /// style :: <see table below> 2840b57cec5SDimitry Andric /// precision :: <non-negative integer> 0-99 2850b57cec5SDimitry Andric /// 2860b57cec5SDimitry Andric /// ===================================================== 2870b57cec5SDimitry Andric /// | style | Meaning | Example | 2880b57cec5SDimitry Andric /// ----------------------------------------------------- 2890b57cec5SDimitry Andric /// | | | Input | Output | 2900b57cec5SDimitry Andric /// ===================================================== 2910b57cec5SDimitry Andric /// | P / p | Percentage | 0.05 | 5.00% | 2920b57cec5SDimitry Andric /// | F / f | Fixed point | 1.0 | 1.00 | 2930b57cec5SDimitry Andric /// | E | Exponential with E | 100000 | 1.0E+05 | 2940b57cec5SDimitry Andric /// | e | Exponential with e | 100000 | 1.0e+05 | 2950b57cec5SDimitry Andric /// | (empty) | Same as F / f | | | 2960b57cec5SDimitry Andric /// ===================================================== 2970b57cec5SDimitry Andric /// 2980b57cec5SDimitry Andric /// The default precision is 6 for exponential (E / e) and 2 for everything 2990b57cec5SDimitry Andric /// else. 3000b57cec5SDimitry Andric 3010b57cec5SDimitry Andric template <typename T> 302*0fca6ea1SDimitry Andric struct format_provider< 303*0fca6ea1SDimitry Andric T, std::enable_if_t<support::detail::use_double_formatter<T>::value>> 304*0fca6ea1SDimitry Andric : public support::detail::HelperFunctions { 3050b57cec5SDimitry Andric static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) { 3060b57cec5SDimitry Andric FloatStyle S; 3070b57cec5SDimitry Andric if (Style.consume_front("P") || Style.consume_front("p")) 3080b57cec5SDimitry Andric S = FloatStyle::Percent; 3090b57cec5SDimitry Andric else if (Style.consume_front("F") || Style.consume_front("f")) 3100b57cec5SDimitry Andric S = FloatStyle::Fixed; 3110b57cec5SDimitry Andric else if (Style.consume_front("E")) 3120b57cec5SDimitry Andric S = FloatStyle::ExponentUpper; 3130b57cec5SDimitry Andric else if (Style.consume_front("e")) 3140b57cec5SDimitry Andric S = FloatStyle::Exponent; 3150b57cec5SDimitry Andric else 3160b57cec5SDimitry Andric S = FloatStyle::Fixed; 3170b57cec5SDimitry Andric 318bdd1243dSDimitry Andric std::optional<size_t> Precision = parseNumericPrecision(Style); 31981ad6265SDimitry Andric if (!Precision) 3200b57cec5SDimitry Andric Precision = getDefaultPrecision(S); 3210b57cec5SDimitry Andric 3220b57cec5SDimitry Andric write_double(Stream, static_cast<double>(V), S, Precision); 3230b57cec5SDimitry Andric } 3240b57cec5SDimitry Andric }; 3250b57cec5SDimitry Andric 326*0fca6ea1SDimitry Andric namespace support { 3270b57cec5SDimitry Andric namespace detail { 3280b57cec5SDimitry Andric template <typename IterT> 3290b57cec5SDimitry Andric using IterValue = typename std::iterator_traits<IterT>::value_type; 3300b57cec5SDimitry Andric 3310b57cec5SDimitry Andric template <typename IterT> 3320b57cec5SDimitry Andric struct range_item_has_provider 3330b57cec5SDimitry Andric : public std::integral_constant< 334*0fca6ea1SDimitry Andric bool, 335*0fca6ea1SDimitry Andric !support::detail::uses_missing_provider<IterValue<IterT>>::value> {}; 336*0fca6ea1SDimitry Andric } // namespace detail 337*0fca6ea1SDimitry Andric } // namespace support 3380b57cec5SDimitry Andric 3390b57cec5SDimitry Andric /// Implementation of format_provider<T> for ranges. 3400b57cec5SDimitry Andric /// 3410b57cec5SDimitry Andric /// This will print an arbitrary range as a delimited sequence of items. 3420b57cec5SDimitry Andric /// 3430b57cec5SDimitry Andric /// The options string of a range type has the grammar: 3440b57cec5SDimitry Andric /// 3450b57cec5SDimitry Andric /// range_style ::= [separator] [element_style] 3460b57cec5SDimitry Andric /// separator ::= "$" delimeted_expr 3470b57cec5SDimitry Andric /// element_style ::= "@" delimeted_expr 3480b57cec5SDimitry Andric /// delimeted_expr ::= "[" expr "]" | "(" expr ")" | "<" expr ">" 3490b57cec5SDimitry Andric /// expr ::= <any string not containing delimeter> 3500b57cec5SDimitry Andric /// 3510b57cec5SDimitry Andric /// where the separator expression is the string to insert between consecutive 3520b57cec5SDimitry Andric /// items in the range and the argument expression is the Style specification to 3530b57cec5SDimitry Andric /// be used when formatting the underlying type. The default separator if 3540b57cec5SDimitry Andric /// unspecified is ' ' (space). The syntax of the argument expression follows 3550b57cec5SDimitry Andric /// whatever grammar is dictated by the format provider or format adapter used 3560b57cec5SDimitry Andric /// to format the value type. 3570b57cec5SDimitry Andric /// 3580b57cec5SDimitry Andric /// Note that attempting to format an `iterator_range<T>` where no format 3590b57cec5SDimitry Andric /// provider can be found for T will result in a compile error. 3600b57cec5SDimitry Andric /// 3610b57cec5SDimitry Andric 3620b57cec5SDimitry Andric template <typename IterT> class format_provider<llvm::iterator_range<IterT>> { 3630b57cec5SDimitry Andric using value = typename std::iterator_traits<IterT>::value_type; 3640b57cec5SDimitry Andric 3650b57cec5SDimitry Andric static StringRef consumeOneOption(StringRef &Style, char Indicator, 3660b57cec5SDimitry Andric StringRef Default) { 3670b57cec5SDimitry Andric if (Style.empty()) 3680b57cec5SDimitry Andric return Default; 3690b57cec5SDimitry Andric if (Style.front() != Indicator) 3700b57cec5SDimitry Andric return Default; 3710b57cec5SDimitry Andric Style = Style.drop_front(); 3720b57cec5SDimitry Andric if (Style.empty()) { 3730b57cec5SDimitry Andric assert(false && "Invalid range style"); 3740b57cec5SDimitry Andric return Default; 3750b57cec5SDimitry Andric } 3760b57cec5SDimitry Andric 377bdd1243dSDimitry Andric for (const char *D : std::array<const char *, 3>{"[]", "<>", "()"}) { 3780b57cec5SDimitry Andric if (Style.front() != D[0]) 3790b57cec5SDimitry Andric continue; 3800b57cec5SDimitry Andric size_t End = Style.find_first_of(D[1]); 3810b57cec5SDimitry Andric if (End == StringRef::npos) { 3820b57cec5SDimitry Andric assert(false && "Missing range option end delimeter!"); 3830b57cec5SDimitry Andric return Default; 3840b57cec5SDimitry Andric } 3850b57cec5SDimitry Andric StringRef Result = Style.slice(1, End); 3860b57cec5SDimitry Andric Style = Style.drop_front(End + 1); 3870b57cec5SDimitry Andric return Result; 3880b57cec5SDimitry Andric } 3890b57cec5SDimitry Andric assert(false && "Invalid range style!"); 3900b57cec5SDimitry Andric return Default; 3910b57cec5SDimitry Andric } 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric static std::pair<StringRef, StringRef> parseOptions(StringRef Style) { 3940b57cec5SDimitry Andric StringRef Sep = consumeOneOption(Style, '$', ", "); 3950b57cec5SDimitry Andric StringRef Args = consumeOneOption(Style, '@', ""); 3960b57cec5SDimitry Andric assert(Style.empty() && "Unexpected text in range option string!"); 3970b57cec5SDimitry Andric return std::make_pair(Sep, Args); 3980b57cec5SDimitry Andric } 3990b57cec5SDimitry Andric 4000b57cec5SDimitry Andric public: 401*0fca6ea1SDimitry Andric static_assert(support::detail::range_item_has_provider<IterT>::value, 4020b57cec5SDimitry Andric "Range value_type does not have a format provider!"); 4030b57cec5SDimitry Andric static void format(const llvm::iterator_range<IterT> &V, 4040b57cec5SDimitry Andric llvm::raw_ostream &Stream, StringRef Style) { 4050b57cec5SDimitry Andric StringRef Sep; 4060b57cec5SDimitry Andric StringRef ArgStyle; 4070b57cec5SDimitry Andric std::tie(Sep, ArgStyle) = parseOptions(Style); 4080b57cec5SDimitry Andric auto Begin = V.begin(); 4090b57cec5SDimitry Andric auto End = V.end(); 4100b57cec5SDimitry Andric if (Begin != End) { 411*0fca6ea1SDimitry Andric auto Adapter = support::detail::build_format_adapter(*Begin); 4120b57cec5SDimitry Andric Adapter.format(Stream, ArgStyle); 4130b57cec5SDimitry Andric ++Begin; 4140b57cec5SDimitry Andric } 4150b57cec5SDimitry Andric while (Begin != End) { 4160b57cec5SDimitry Andric Stream << Sep; 417*0fca6ea1SDimitry Andric auto Adapter = support::detail::build_format_adapter(*Begin); 4180b57cec5SDimitry Andric Adapter.format(Stream, ArgStyle); 4190b57cec5SDimitry Andric ++Begin; 4200b57cec5SDimitry Andric } 4210b57cec5SDimitry Andric } 4220b57cec5SDimitry Andric }; 423*0fca6ea1SDimitry Andric } // namespace llvm 4240b57cec5SDimitry Andric 4250b57cec5SDimitry Andric #endif 426