xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/Support/FormatProviders.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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