From 3e5cf3400273b0e4f8f96a3a87d2b9e57574eeec Mon Sep 17 00:00:00 2001 From: David Robillard Date: Tue, 16 Aug 2022 16:44:29 -0400 Subject: Upgrade to fmt 9.0.0 This library tends to break in annoying ways like this, so pin the major version to 9 to hopefully avoid these problems in the future. --- subprojects/fmt/include/fmt/ostream.h | 224 ++++++++++++++++++++-------------- 1 file changed, 130 insertions(+), 94 deletions(-) (limited to 'subprojects/fmt/include/fmt/ostream.h') diff --git a/subprojects/fmt/include/fmt/ostream.h b/subprojects/fmt/include/fmt/ostream.h index 29c58ec..394d947 100644 --- a/subprojects/fmt/include/fmt/ostream.h +++ b/subprojects/fmt/include/fmt/ostream.h @@ -8,89 +8,97 @@ #ifndef FMT_OSTREAM_H_ #define FMT_OSTREAM_H_ +#include #include #include "format.h" FMT_BEGIN_NAMESPACE -template class basic_printf_parse_context; template class basic_printf_context; namespace detail { -template class formatbuf : public std::basic_streambuf { +// Checks if T has a user-defined operator<<. +template +class is_streamable { private: - using int_type = typename std::basic_streambuf::int_type; - using traits_type = typename std::basic_streambuf::traits_type; + template + static auto test(int) + -> bool_constant&>() + << std::declval()) != 0>; + + template static auto test(...) -> std::false_type; - buffer& buffer_; + using result = decltype(test(0)); public: - formatbuf(buffer& buf) : buffer_(buf) {} - - protected: - // The put-area is actually always empty. This makes the implementation - // simpler and has the advantage that the streambuf and the buffer are always - // in sync and sputc never writes into uninitialized memory. The obvious - // disadvantage is that each call to sputc always results in a (virtual) call - // to overflow. There is no disadvantage here for sputn since this always - // results in a call to xsputn. - - int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE { - if (!traits_type::eq_int_type(ch, traits_type::eof())) - buffer_.push_back(static_cast(ch)); - return ch; - } + is_streamable() = default; - std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE { - buffer_.append(s, s + count); - return count; - } + static const bool value = result::value; }; -struct converter { - template ::value)> converter(T); -}; +// Formatting of built-in types and arrays is intentionally disabled because +// it's handled by standard (non-ostream) formatters. +template +struct is_streamable< + T, Char, + enable_if_t< + std::is_arithmetic::value || std::is_array::value || + std::is_pointer::value || std::is_same::value || + std::is_convertible>::value || + std::is_same>::value || + (std::is_convertible::value && !std::is_enum::value)>> + : std::false_type {}; + +template FILE* get_file(std::basic_filebuf&) { + return nullptr; +} -template struct test_stream : std::basic_ostream { - private: - void_t<> operator<<(converter); +struct dummy_filebuf { + FILE* _Myfile; }; - -// Hide insertion operators for built-in types. -template -void_t<> operator<<(std::basic_ostream&, Char); -template -void_t<> operator<<(std::basic_ostream&, char); -template -void_t<> operator<<(std::basic_ostream&, char); -template -void_t<> operator<<(std::basic_ostream&, signed char); -template -void_t<> operator<<(std::basic_ostream&, unsigned char); - -// Checks if T has a user-defined operator<< (e.g. not a member of -// std::ostream). -template class is_streamable { - private: - template - static bool_constant&>() - << std::declval()), - void_t<>>::value> - test(int); - - template static std::false_type test(...); - - using result = decltype(test(0)); - - public: - static const bool value = result::value; +template struct ms_filebuf { + using type = dummy_filebuf; }; +template struct ms_filebuf { + using type = T; +}; +using filebuf_type = ms_filebuf::type; + +FILE* get_file(filebuf_type& buf); + +// Generate a unique explicit instantion in every translation unit using a tag +// type in an anonymous namespace. +namespace { +struct filebuf_access_tag {}; +} // namespace +template +class filebuf_access { + friend FILE* get_file(filebuf_type& buf) { return buf.*file; } +}; +template class filebuf_access; + +inline bool write(std::filebuf& buf, fmt::string_view data) { + FILE* f = get_file(buf); + if (!f) return false; + print(f, data); + return true; +} +inline bool write(std::wfilebuf&, fmt::basic_string_view) { + return false; +} // Write the content of buf to os. +// It is a separate function rather than a part of vprint to simplify testing. template void write_buffer(std::basic_ostream& os, buffer& buf) { + if (const_check(FMT_MSC_VERSION)) { + auto filebuf = dynamic_cast*>(os.rdbuf()); + if (filebuf && write(*filebuf, {buf.data(), buf.size()})) return; + } const Char* buf_data = buf.data(); using unsigned_streamsize = std::make_unsigned::type; unsigned_streamsize size = buf.size(); @@ -106,53 +114,74 @@ void write_buffer(std::basic_ostream& os, buffer& buf) { template void format_value(buffer& buf, const T& value, locale_ref loc = locale_ref()) { - formatbuf format_buf(buf); - std::basic_ostream output(&format_buf); + auto&& format_buf = formatbuf>(buf); + auto&& output = std::basic_ostream(&format_buf); #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) if (loc) output.imbue(loc.get()); #endif output << value; output.exceptions(std::ios_base::failbit | std::ios_base::badbit); - buf.try_resize(buf.size()); } -// Formats an object of type T that has an overloaded ostream operator<<. -template -struct fallback_formatter::value>> - : private formatter, Char> { - FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) - -> decltype(ctx.begin()) { - return formatter, Char>::parse(ctx); - } - template >::value)> - auto parse(ParseCtx& ctx) -> decltype(ctx.begin()) { - return ctx.begin(); - } +template struct streamed_view { const T& value; }; - template - auto format(const T& value, basic_format_context& ctx) +} // namespace detail + +// Formats an object of type T that has an overloaded ostream operator<<. +template +struct basic_ostream_formatter : formatter, Char> { + template + auto format(const T& value, basic_format_context& ctx) const -> OutputIt { - basic_memory_buffer buffer; + auto buffer = basic_memory_buffer(); format_value(buffer, value, ctx.locale()); - basic_string_view str(buffer.data(), buffer.size()); - return formatter, Char>::format(str, ctx); + return formatter, Char>::format( + {buffer.data(), buffer.size()}, ctx); } +}; + +using ostream_formatter = basic_ostream_formatter; + +template +struct formatter> : ostream_formatter { template - auto format(const T& value, basic_printf_context& ctx) - -> OutputIt { - basic_memory_buffer buffer; - format_value(buffer, value, ctx.locale()); - return std::copy(buffer.begin(), buffer.end(), ctx.out()); + auto format(detail::streamed_view view, + basic_format_context& ctx) const -> OutputIt { + return ostream_formatter::format(view.value, ctx); } }; + +/** + \rst + Returns a view that formats `value` via an ostream ``operator<<``. + + **Example**:: + + fmt::print("Current thread id: {}\n", + fmt::streamed(std::this_thread::get_id())); + \endrst + */ +template +auto streamed(const T& value) -> detail::streamed_view { + return {value}; +} + +namespace detail { + +// Formats an object of type T that has an overloaded ostream operator<<. +template +struct fallback_formatter::value>> + : basic_ostream_formatter { + using basic_ostream_formatter::format; +}; + } // namespace detail -template -void vprint(std::basic_ostream& os, basic_string_view format_str, +FMT_MODULE_EXPORT template +void vprint(std::basic_ostream& os, + basic_string_view> format_str, basic_format_args>> args) { - basic_memory_buffer buffer; + auto buffer = basic_memory_buffer(); detail::vformat_to(buffer, format_str, args); detail::write_buffer(os, buffer); } @@ -166,12 +195,19 @@ void vprint(std::basic_ostream& os, basic_string_view format_str, fmt::print(cerr, "Don't {}!", "panic"); \endrst */ -template ::value, char_t>> -void print(std::basic_ostream& os, const S& format_str, Args&&... args) { - vprint(os, to_string_view(format_str), - fmt::make_args_checked(format_str, args...)); +FMT_MODULE_EXPORT template +void print(std::ostream& os, format_string fmt, T&&... args) { + vprint(os, fmt, fmt::make_format_args(args...)); } + +FMT_MODULE_EXPORT +template +void print(std::wostream& os, + basic_format_string...> fmt, + Args&&... args) { + vprint(os, fmt, fmt::make_format_args>(args...)); +} + FMT_END_NAMESPACE #endif // FMT_OSTREAM_H_ -- cgit v1.2.1