Index: llvm/include/llvm/Support/FormatAdapters.h =================================================================== --- llvm/include/llvm/Support/FormatAdapters.h +++ llvm/include/llvm/Support/FormatAdapters.h @@ -36,8 +36,8 @@ Fill(Fill) {} void format(llvm::raw_ostream &Stream, StringRef Style) { - auto Adapter = detail::build_format_adapter(std::forward(this->Item)); - FmtAlign(Adapter, Where, Amount, Fill).format(Stream, Style); + value_holder Holder(std::forward(this->Item)); + FmtAlign(Holder, Where, Amount, Fill).format(Stream, Style); } }; @@ -50,9 +50,8 @@ : FormatAdapter(std::forward(Item)), Left(Left), Right(Right) {} void format(llvm::raw_ostream &Stream, StringRef Style) { - auto Adapter = detail::build_format_adapter(std::forward(this->Item)); Stream.indent(Left); - Adapter.format(Stream, Style); + format_one_item(std::forward(this->Item), Stream, Style); Stream.indent(Right); } }; @@ -65,9 +64,8 @@ : FormatAdapter(std::forward(Item)), Count(Count) {} void format(llvm::raw_ostream &Stream, StringRef Style) { - auto Adapter = detail::build_format_adapter(std::forward(this->Item)); for (size_t I = 0; I < Count; ++I) { - Adapter.format(Stream, Style); + format_one_item(std::forward(this->Item), Stream, Style); } } }; Index: llvm/include/llvm/Support/FormatProviders.h =================================================================== --- llvm/include/llvm/Support/FormatProviders.h +++ llvm/include/llvm/Support/FormatProviders.h @@ -25,8 +25,26 @@ #include #include +#define FORMATTER(Type) \ + namespace llvm { \ + void format_one_item(Type &&Item, raw_ostream &S, StringRef Options); \ + } \ + inline void llvm::format_one_item(Type &&Value, raw_ostream &Stream, \ + StringRef Style) + +#define FORMAT_IF(Condition) \ + namespace llvm { \ + template \ + typename std::enable_if::type \ + format_one_item(T &&Item, raw_ostream &S, StringRef Options); \ + } \ + template \ + typename std::enable_if::type llvm::format_one_item( \ + T &&Value, llvm::raw_ostream &Stream, llvm::StringRef Style) + namespace llvm { namespace detail { + template struct use_integral_formatter : public std::integral_constant< @@ -186,93 +204,6 @@ } }; -/// Implementation of format_provider 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 -struct format_provider< - T, typename std::enable_if::value>::type> { - 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 for llvm::Twine. -/// -/// This follows the same rules as the string formatter. - -template <> struct format_provider { - static void format(const Twine &V, llvm::raw_ostream &Stream, - StringRef Style) { - format_provider::format(V.str(), Stream, Style); - } -}; - -/// Implementation of format_provider 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 -struct format_provider< - T, typename std::enable_if::value>::type> { - static void format(const char &V, llvm::raw_ostream &Stream, - StringRef Style) { - if (Style.empty()) - Stream << V; - else { - int X = static_cast(V); - format_provider::format(X, Stream, Style); - } - } -}; - -/// Implementation of format_provider 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 { - static void format(const bool &B, llvm::raw_ostream &Stream, - StringRef Style) { - Stream << StringSwitch(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 for floating point types. /// /// The options string of a floating point type has the format: @@ -321,16 +252,6 @@ } }; -namespace detail { -template -using IterValue = typename std::iterator_traits::value_type; - -template -struct range_item_has_provider - : public std::integral_constant< - bool, !uses_missing_provider>::value> {}; -} - /// Implementation of format_provider for ranges. /// /// This will print an arbitrary range as a delimited sequence of items. @@ -394,8 +315,6 @@ } public: - static_assert(detail::range_item_has_provider::value, - "Range value_type does not have a format provider!"); static void format(const llvm::iterator_range &V, llvm::raw_ostream &Stream, StringRef Style) { StringRef Sep; @@ -404,20 +323,84 @@ auto Begin = V.begin(); auto End = V.end(); if (Begin != End) { - auto Adapter = - detail::build_format_adapter(std::forward(*Begin)); - Adapter.format(Stream, ArgStyle); + format_one_item(*Begin, Stream, ArgStyle); ++Begin; } while (Begin != End) { Stream << Sep; - auto Adapter = - detail::build_format_adapter(std::forward(*Begin)); - Adapter.format(Stream, ArgStyle); + format_one_item(*Begin, Stream, ArgStyle); ++Begin; } } }; } +/// Implementation of format_provider 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' | +/// ================================== +FORMATTER(bool) { + Stream << StringSwitch(Style) + .Case("Y", Value ? "YES" : "NO") + .Case("y", Value ? "yes" : "no") + .CaseLower("D", Value ? "1" : "0") + .Case("T", Value ? "TRUE" : "FALSE") + .Cases("t", "", Value ? "true" : "false") + .Default(Value ? "1" : "0"); +} + +/// Implementation of format_provider 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. +/// +FORMATTER(char) { + if (Style.empty()) + Stream << Value; + else { + int X = static_cast(Value); + format_provider::format(X, Stream, Style); + } +} + +/// Implementation of format_provider 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. +FORMAT_IF(llvm::detail::use_string_formatter) { + size_t N = StringRef::npos; + if (!Style.empty() && Style.getAsInteger(10, N)) { + assert(false && "Style is not a valid integer"); + } + llvm::StringRef S = Value; + Stream << S.substr(0, N); +} + +/// Implementation of format_provider for llvm::Twine. +/// +/// This follows the same rules as the string formatter. +FORMATTER(llvm::Twine) { format_one_item(Value.str(), Stream, Style); }; + #endif Index: llvm/include/llvm/Support/FormatVariadic.h =================================================================== --- llvm/include/llvm/Support/FormatVariadic.h +++ llvm/include/llvm/Support/FormatVariadic.h @@ -137,16 +137,17 @@ operator std::string() const { return str(); } }; -template class formatv_object : public formatv_object_base { +template class formatv_object : public formatv_object_base { + using Tuple = std::tuple...>; // Storage for the parameter adapters. Since the base class erases the type // of the parameters, we have to own the storage for the parameters here, and // have the base class store type-erased pointers into this tuple. Tuple Parameters; public: - formatv_object(StringRef Fmt, Tuple &&Params) - : formatv_object_base(Fmt, std::tuple_size::value), - Parameters(std::move(Params)) { + formatv_object(StringRef Fmt, Ts &&... Params) + : formatv_object_base(Fmt, sizeof...(Params)), + Parameters(detail::value_holder(std::forward(Params))...) { Adapters = apply_tuple(create_adapters(), Parameters); } }; @@ -233,13 +234,8 @@ // the details of what that is are undefined. // template -inline auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object(Vals))...))> { - using ParamTuple = decltype( - std::make_tuple(detail::build_format_adapter(std::forward(Vals))...)); - return formatv_object( - Fmt, - std::make_tuple(detail::build_format_adapter(std::forward(Vals))...)); +inline formatv_object formatv(const char *Fmt, Ts &&... Vals) { + return formatv_object(Fmt, std::forward(Vals)...); } } // end namespace llvm Index: llvm/include/llvm/Support/FormatVariadicDetails.h =================================================================== --- llvm/include/llvm/Support/FormatVariadicDetails.h +++ llvm/include/llvm/Support/FormatVariadicDetails.h @@ -27,14 +27,12 @@ virtual void format(raw_ostream &S, StringRef Options) = 0; }; -template class provider_format_adapter : public format_adapter { +template class value_holder : public format_adapter { T Item; - public: - explicit provider_format_adapter(T &&Item) : Item(Item) {} - - void format(llvm::raw_ostream &S, StringRef Options) override { - format_provider::type>::format(Item, S, Options); + explicit value_holder(T &&Item) : Item(Item) {} + virtual void format(raw_ostream &S, StringRef Options) { + format_one_item(std::forward(Item), S, Options); } }; @@ -76,36 +74,19 @@ : public std::integral_constant< bool, !uses_format_member::value && has_FormatProvider::value> { }; - -// Simple template that decides whether a type T has neither a member-function -// nor format_provider based implementation that it can use. Mostly used so -// that the compiler spits out a nice diagnostic when a type with no format -// implementation can be located. -template -struct uses_missing_provider - : public std::integral_constant::value && - !uses_format_provider::value> {}; - -template -typename std::enable_if::value, T>::type -build_format_adapter(T &&Item) { - return std::forward(Item); } template -typename std::enable_if::value, - provider_format_adapter>::type -build_format_adapter(T &&Item) { - return provider_format_adapter(std::forward(Item)); +typename std::enable_if::value, void>::type +format_one_item(T &&Item, raw_ostream &S, StringRef Options) { + Item.format(S, Options); } template -typename std::enable_if::value, - missing_format_adapter>::type -build_format_adapter(T &&Item) { - return missing_format_adapter(); -} +typename std::enable_if::value, void>::type +format_one_item(T &&Item, raw_ostream &S, StringRef Options) { + format_provider::type>::format(std::forward(Item), + S, Options); } } Index: llvm/unittests/Support/FormatVariadicTest.cpp =================================================================== --- llvm/unittests/Support/FormatVariadicTest.cpp +++ llvm/unittests/Support/FormatVariadicTest.cpp @@ -21,7 +21,6 @@ }; using detail::uses_format_member; -using detail::uses_missing_provider; static_assert(uses_format_member::value, ""); static_assert(uses_format_member::value, ""); @@ -30,9 +29,6 @@ static_assert(uses_format_member::value, ""); static_assert(uses_format_member::value, ""); static_assert(uses_format_member::value, ""); - -struct NoFormat {}; -static_assert(uses_missing_provider::value, ""); } TEST(FormatVariadicTest, EmptyFormatString) {