diff --git a/include/fmt/base.h b/include/fmt/base.h index 8500af7a..a9a3a96b 100644 --- a/include/fmt/base.h +++ b/include/fmt/base.h @@ -254,7 +254,8 @@ #ifdef FMT_CLANG_PRAGMA // Use the provided definition. #elif FMT_CLANG_VERSION -# define FMT_CLANG_PRAGMA(x) _Pragma(#x) +# define FMT_CLANG_PRAGMA_IMPL(x) _Pragma(#x) +# define FMT_CLANG_PRAGMA(x) FMT_CLANG_PRAGMA_IMPL(clang x) #else # define FMT_CLANG_PRAGMA(x) #endif @@ -317,7 +318,7 @@ FMT_GCC_PRAGMA(GCC push_options) #if !defined(__OPTIMIZE__) && !defined(__CUDACC__) FMT_GCC_PRAGMA(GCC optimize("Og")) #endif -FMT_CLANG_PRAGMA(clang diagnostic push) +FMT_CLANG_PRAGMA(diagnostic push) FMT_BEGIN_NAMESPACE @@ -432,7 +433,7 @@ template auto convert_for_visit(T) -> monostate { return {}; } #endif #if FMT_USE_BITINT -# pragma clang diagnostic ignored "-Wbit-int-extension" +FMT_CLANG_PRAGMA(diagnostic ignored "-Wbit-int-extension") template using bitint = _BitInt(N); template using ubitint = unsigned _BitInt(N); #else @@ -2431,7 +2432,7 @@ template struct native_formatter { specs_.set_type(set ? presentation_type::debug : presentation_type::none); } - FMT_CLANG_PRAGMA(clang diagnostic ignored "-Wundefined-inline") + FMT_CLANG_PRAGMA(diagnostic ignored "-Wundefined-inline") template FMT_CONSTEXPR auto format(const T& val, FormatContext& ctx) const -> decltype(ctx.out()); @@ -2452,17 +2453,8 @@ FMT_CONSTEXPR inline auto is_locking() -> bool { return locking::value || is_locking(); } -// Use vformat_args and avoid type_identity to keep symbols short. -template struct vformat_args { - using type = basic_format_args>; -}; -template <> struct vformat_args { - using type = format_args; -}; - -template -void vformat_to(buffer& buf, basic_string_view fmt, - typename vformat_args::type args, locale_ref loc = {}); +FMT_API void vformat_to(buffer& buf, string_view fmt, format_args args, + locale_ref loc = {}); #ifdef _WIN32 FMT_API void vprint_mojibake(FILE*, string_view, format_args, bool); @@ -2978,7 +2970,7 @@ template FMT_NODISCARD FMT_INLINE auto formatted_size(format_string fmt, T&&... args) -> size_t { auto buf = detail::counting_buffer<>(); - detail::vformat_to(buf, fmt, fmt::make_format_args(args...), {}); + detail::vformat_to(buf, fmt, fmt::make_format_args(args...), {}); return buf.count(); } @@ -3036,7 +3028,7 @@ FMT_INLINE void println(format_string fmt, T&&... args) { } FMT_END_EXPORT -FMT_CLANG_PRAGMA(clang diagnostic pop) +FMT_CLANG_PRAGMA(diagnostic pop) FMT_GCC_PRAGMA(GCC pop_options) FMT_END_NAMESPACE diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 8b1c2feb..7042d2b8 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -1442,6 +1442,15 @@ FMT_FUNC auto vformat(string_view fmt, format_args args) -> std::string { namespace detail { +FMT_FUNC void vformat_to(buffer& buf, string_view fmt, format_args args, + locale_ref loc) { + auto out = appender(buf); + if (fmt.size() == 2 && equal2(fmt.data(), "{}")) + return args.get(0).visit(default_arg_formatter{out}); + parse_format_string( + fmt, format_handler{parse_context(fmt), {out, args, loc}}); +} + template struct span { T* data; size_t size; diff --git a/include/fmt/format.h b/include/fmt/format.h index c9d2434f..6117ef45 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3808,6 +3808,71 @@ template struct udl_arg { # endif #endif // FMT_USE_USER_DEFINED_LITERALS +template struct format_handler { + parse_context parse_ctx; + buffered_context ctx; + + void on_text(const Char* begin, const Char* end) { + copy_noinline(begin, end, ctx.out()); + } + + FMT_CONSTEXPR auto on_arg_id() -> int { return parse_ctx.next_arg_id(); } + FMT_CONSTEXPR auto on_arg_id(int id) -> int { + parse_ctx.check_arg_id(id); + return id; + } + FMT_CONSTEXPR auto on_arg_id(basic_string_view id) -> int { + parse_ctx.check_arg_id(id); + int arg_id = ctx.arg_id(id); + if (arg_id < 0) report_error("argument not found"); + return arg_id; + } + + FMT_INLINE void on_replacement_field(int id, const Char*) { + ctx.arg(id).visit(default_arg_formatter{ctx.out()}); + } + + auto on_format_specs(int id, const Char* begin, const Char* end) + -> const Char* { + auto arg = get_arg(ctx, id); + // Not using a visitor for custom types gives better codegen. + if (arg.format_custom(begin, parse_ctx, ctx)) return parse_ctx.begin(); + + auto specs = dynamic_format_specs(); + begin = parse_format_specs(begin, end, specs, parse_ctx, arg.type()); + if (specs.dynamic()) { + handle_dynamic_spec(specs.dynamic_width(), specs.width, specs.width_ref, + ctx); + handle_dynamic_spec(specs.dynamic_precision(), specs.precision, + specs.precision_ref, ctx); + } + + arg.visit(arg_formatter{ctx.out(), specs, ctx.locale()}); + return begin; + } + + FMT_NORETURN void on_error(const char* message) { report_error(message); } +}; + +// DEPRECATED! +// Use vformat_args and avoid type_identity to keep symbols short. +template struct vformat_args { + using type = basic_format_args>; +}; +template <> struct vformat_args { + using type = format_args; +}; + +template +void vformat_to(buffer& buf, basic_string_view fmt, + typename vformat_args::type args, locale_ref loc = {}) { + auto out = basic_appender(buf); + if (fmt.size() == 2 && equal2(fmt.data(), "{}")) + return args.get(0).visit(default_arg_formatter{out}); + parse_format_string( + fmt, format_handler{parse_context(fmt), {out, args, loc}}); +} + template auto vformat(const Locale& loc, basic_string_view fmt, typename detail::vformat_args::type args) @@ -4188,68 +4253,9 @@ FMT_END_EXPORT namespace detail { -template struct format_handler { - parse_context parse_ctx; - buffered_context ctx; - - void on_text(const Char* begin, const Char* end) { - copy_noinline(begin, end, ctx.out()); - } - - FMT_CONSTEXPR auto on_arg_id() -> int { return parse_ctx.next_arg_id(); } - FMT_CONSTEXPR auto on_arg_id(int id) -> int { - parse_ctx.check_arg_id(id); - return id; - } - FMT_CONSTEXPR auto on_arg_id(basic_string_view id) -> int { - parse_ctx.check_arg_id(id); - int arg_id = ctx.arg_id(id); - if (arg_id < 0) report_error("argument not found"); - return arg_id; - } - - FMT_INLINE void on_replacement_field(int id, const Char*) { - ctx.arg(id).visit(default_arg_formatter{ctx.out()}); - } - - auto on_format_specs(int id, const Char* begin, const Char* end) - -> const Char* { - auto arg = get_arg(ctx, id); - // Not using a visitor for custom types gives better codegen. - if (arg.format_custom(begin, parse_ctx, ctx)) return parse_ctx.begin(); - - auto specs = dynamic_format_specs(); - begin = parse_format_specs(begin, end, specs, parse_ctx, arg.type()); - if (specs.dynamic()) { - handle_dynamic_spec(specs.dynamic_width(), specs.width, specs.width_ref, - ctx); - handle_dynamic_spec(specs.dynamic_precision(), specs.precision, - specs.precision_ref, ctx); - } - - arg.visit(arg_formatter{ctx.out(), specs, ctx.locale()}); - return begin; - } - - FMT_NORETURN void on_error(const char* message) { report_error(message); } -}; - -template -void vformat_to(buffer& buf, basic_string_view fmt, - typename vformat_args::type args, locale_ref loc) { - auto out = basic_appender(buf); - if (fmt.size() == 2 && equal2(fmt.data(), "{}")) - return args.get(0).visit(default_arg_formatter{out}); - parse_format_string( - fmt, format_handler{parse_context(fmt), {out, args, loc}}); -} - FMT_BEGIN_EXPORT #ifndef FMT_HEADER_ONLY -extern template FMT_API void vformat_to(buffer&, string_view, - typename vformat_args<>::type, - locale_ref); extern template FMT_API auto thousands_sep_impl(locale_ref) -> thousands_sep_result; extern template FMT_API auto thousands_sep_impl(locale_ref) @@ -4361,8 +4367,8 @@ FMT_NODISCARD FMT_INLINE auto formatted_size(const Locale& loc, format_string fmt, T&&... args) -> size_t { auto buf = detail::counting_buffer<>(); - detail::vformat_to(buf, fmt, fmt::make_format_args(args...), - detail::locale_ref(loc)); + detail::vformat_to(buf, fmt, fmt::make_format_args(args...), + detail::locale_ref(loc)); return buf.count(); } diff --git a/src/format.cc b/src/format.cc index 70d12d6b..4bc82a3c 100644 --- a/src/format.cc +++ b/src/format.cc @@ -29,6 +29,7 @@ template FMT_API auto decimal_point_impl(locale_ref) -> char; // DEPRECATED! template FMT_API void buffer::append(const char*, const char*); +// DEPRECATED! template FMT_API void vformat_to(buffer&, string_view, typename vformat_args<>::type, locale_ref);