diff --git a/include/fmt/compile.h b/include/fmt/compile.h index 128004bc..f7084874 100644 --- a/include/fmt/compile.h +++ b/include/fmt/compile.h @@ -157,7 +157,8 @@ struct is_compiled_string : std::is_base_of {}; \endrst */ #ifdef __cpp_if_constexpr -# define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::detail::compiled_string) +# define FMT_COMPILE(s) \ + FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit) #else # define FMT_COMPILE(s) FMT_STRING(s) #endif @@ -428,7 +429,7 @@ template constexpr auto parse_replacement_field_then_tail(S format_str) { using char_type = typename S::char_type; - constexpr basic_string_view str = format_str; + constexpr auto str = basic_string_view(format_str); constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type(); if constexpr (c == '}') { return parse_tail( @@ -449,7 +450,7 @@ constexpr auto parse_replacement_field_then_tail(S format_str) { template constexpr auto compile_format_string(S format_str) { using char_type = typename S::char_type; - constexpr basic_string_view str = format_str; + constexpr auto str = basic_string_view(format_str); if constexpr (str[POS] == '{') { if constexpr (POS + 1 == str.size()) throw format_error("unmatched '{' in format string"); @@ -518,7 +519,7 @@ constexpr auto compile_format_string(S format_str) { template ::value)> constexpr auto compile(S format_str) { - constexpr basic_string_view str = format_str; + constexpr auto str = basic_string_view(format_str); if constexpr (str.size() == 0) { return detail::make_text(str, 0, 0); } else { @@ -557,7 +558,7 @@ template format(const S&, Args&&... args) { if constexpr (std::is_same::value) { - constexpr basic_string_view str = S(); + constexpr auto str = basic_string_view(S()); if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') { const auto& first = detail::first(args...); if constexpr (detail::is_named_arg< diff --git a/include/fmt/core.h b/include/fmt/core.h index 4615e653..cbb7aabb 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -550,7 +550,7 @@ struct is_compile_string : std::is_base_of {}; template ::value)> constexpr basic_string_view to_string_view(const S& s) { - return s; + return basic_string_view(s); } FMT_BEGIN_DETAIL_NAMESPACE @@ -841,6 +841,8 @@ class iterator_buffer final : public Traits, public buffer { public: explicit iterator_buffer(OutputIt out, size_t n = buffer_size) : Traits(n), buffer(data_, 0, buffer_size), out_(out) {} + iterator_buffer(iterator_buffer&& other) + : Traits(other), buffer(data_, 0, buffer_size), out_(other.out_) {} ~iterator_buffer() { flush(); } OutputIt out() { @@ -901,6 +903,7 @@ template class counting_buffer final : public buffer { public: counting_buffer() : buffer(data_, 0, buffer_size) {} + counting_buffer(counting_buffer&&) : buffer(data_, 0, buffer_size) {} size_t count() { return count_ + this->size(); } }; @@ -2679,13 +2682,13 @@ constexpr auto compile_string_to_view(std_string_view s) return {s.data(), s.size()}; } -#define FMT_STRING_IMPL(s, base) \ +#define FMT_STRING_IMPL(s, base, explicit) \ [] { \ /* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \ /* Use a macro-like name to avoid shadowing warnings. */ \ struct FMT_GCC_VISIBILITY_HIDDEN FMT_COMPILE_STRING : base { \ using char_type = fmt::remove_cvref_t; \ - FMT_MAYBE_UNUSED FMT_CONSTEXPR \ + FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit \ operator fmt::basic_string_view() const { \ return fmt::detail::compile_string_to_view(s); \ } \ @@ -2703,18 +2706,11 @@ constexpr auto compile_string_to_view(std_string_view s) std::string s = fmt::format(FMT_STRING("{:d}"), "foo"); \endrst */ -#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::compile_string) - -template ::value)> -auto vformat(basic_string_view format_str, - basic_format_args>> args) - -> std::basic_string; - -FMT_API auto vformat(string_view format_str, format_args args) -> std::string; +#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::compile_string, ) template void vformat_to( - buffer& buf, basic_string_view format_str, + buffer>& buf, basic_string_view format_str, basic_format_args)> args, detail::locale_ref loc = {}); @@ -2806,99 +2802,14 @@ struct formatter decltype(ctx.out()); }; -/** Formats a string and writes the output to ``out``. */ -template , - bool enable = detail::is_output_iterator::value> -auto vformat_to(OutputIt out, const S& format_str, - basic_format_args>> args) - -> enable_if_t { - decltype(detail::get_buffer(out)) buf(detail::get_buffer_init(out)); - detail::vformat_to(buf, to_string_view(format_str), args); - return detail::get_iterator(buf); -} - -/** - \rst - Formats arguments, writes the result to the output iterator ``out`` and returns - the iterator past the end of the output range. - - **Example**:: - - std::vector out; - fmt::format_to(std::back_inserter(out), "{}", 42); - \endrst - */ -// We cannot use FMT_ENABLE_IF because of a bug in gcc 8.3. -template >::value)> -inline auto format_to(OutputIt out, const S& format_str, Args&&... args) - -> OutputIt { - const auto& vargs = fmt::make_args_checked(format_str, args...); - return vformat_to(out, to_string_view(format_str), vargs); -} - -template struct format_to_n_result { - /** Iterator past the end of the output range. */ - OutputIt out; - /** Total (not truncated) output size. */ - size_t size; -}; - -template ::value)> -inline auto vformat_to_n( - OutputIt out, size_t n, basic_string_view format_str, - basic_format_args>> args) - -> format_to_n_result { - detail::iterator_buffer buf(out, - n); - detail::vformat_to(buf, format_str, args); - return {buf.out(), buf.count()}; -} - -/** - \rst - Formats arguments, writes up to ``n`` characters of the result to the output - iterator ``out`` and returns the total output size and the iterator past the - end of the output range. - \endrst - */ -template >::value)> -inline auto format_to_n(OutputIt out, size_t n, const S& format_str, - const Args&... args) -> format_to_n_result { - const auto& vargs = fmt::make_args_checked(format_str, args...); - return vformat_to_n(out, n, to_string_view(format_str), vargs); -} - -/** - Returns the number of characters in the output of - ``format(format_str, args...)``. - */ -template > -inline auto formatted_size(const S& format_str, Args&&... args) -> size_t { - detail::counting_buffer<> buf; - const auto& vargs = fmt::make_args_checked(format_str, args...); - detail::vformat_to(buf, to_string_view(format_str), vargs); - return buf.count(); -} - -template > -FMT_INLINE auto vformat( - const S& format_str, - basic_format_args>> args) - -> std::basic_string { - return detail::vformat(to_string_view(format_str), args); -} - template class basic_format_string { private: - basic_string_view str; + basic_string_view str_; public: #if FMT_COMPILE_TIME_CHECKS template - consteval basic_format_string(const char (&s)[N]) : str(s) { + consteval basic_format_string(const char (&s)[N]) : str_(s) { if constexpr (detail::count_named_args() == 0) { using checker = detail::format_string_checker...>; @@ -2907,10 +2818,10 @@ template class basic_format_string { } #endif - template , - const T&>::value)> - basic_format_string(const T& s) : str(s) { + template >::value)> + basic_format_string(const S& s) : str_(s) { static_assert( detail::count< (std::is_base_of>::value && @@ -2919,7 +2830,7 @@ template class basic_format_string { detail::check_format_string(s); } - FMT_INLINE operator basic_string_view() const { return str; } + FMT_INLINE operator basic_string_view() const { return str_; } }; #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 @@ -2930,9 +2841,12 @@ template using format_string = basic_format_string...>; #endif +FMT_API auto vformat(string_view fmt, format_args args) -> std::string; + /** \rst - Formats arguments and returns the result as a string. + Formats ``args`` according to specifications in ``fmt`` and returns the result + as a string. **Example**:: @@ -2941,34 +2855,84 @@ using format_string = basic_format_string...>; \endrst */ template -FMT_INLINE auto format(format_string str, T&&... args) -> std::string { - return detail::vformat(str, make_format_args(args...)); +FMT_INLINE auto format(format_string fmt, T&&... args) -> std::string { + return vformat(fmt, make_format_args(args...)); } -FMT_API void vprint(std::FILE*, string_view, format_args); -FMT_API void vprint(string_view, format_args); +/** Formats a string and writes the output to ``out``. */ +template ::value)> +auto vformat_to(OutputIt out, string_view fmt, format_args args) -> OutputIt { + decltype(detail::get_buffer(out)) buf(detail::get_buffer_init(out)); + detail::vformat_to(buf, string_view(fmt), args); + return detail::get_iterator(buf); +} + +/** + \rst + Formats ``args`` according to specifications in ``fmt``, writes the result to + the output iterator ``out`` and returns the iterator past the end of the output + range. + + **Example**:: + + auto out = std::vector(); + fmt::format_to(std::back_inserter(out), "{}", 42); + \endrst + */ +template ::value)> +inline auto format_to(OutputIt out, format_string fmt, T&&... args) + -> OutputIt { + return vformat_to(out, fmt, make_format_args(args...)); +} + +template struct format_to_n_result { + /** Iterator past the end of the output range. */ + OutputIt out; + /** Total (not truncated) output size. */ + size_t size; +}; + +template ::value)> +auto vformat_to_n(OutputIt out, size_t n, string_view fmt, format_args args) + -> format_to_n_result { + using buffer = + detail::iterator_buffer; + auto buf = buffer(out, n); + detail::vformat_to(buf, fmt, args); + return {buf.out(), buf.count()}; +} /** \rst - Formats ``args`` according to specifications in ``str`` and writes the - output to the file ``f``. Strings are assumed to be in UTF-8 unless the - ``FMT_UNICODE`` macro is set to 0. - - **Example**:: - - fmt::print(stderr, "Don't {}!", "panic"); + Formats ``args`` according to specifications in ``fmt``, writes up to ``n`` + characters of the result to the output iterator ``out`` and returns the total + (not truncated) output size and the iterator past the end of the output range. \endrst */ -template -inline void print(std::FILE* f, format_string str, T&&... args) { - const auto& vargs = make_format_args(args...); - return detail::is_utf8() ? vprint(f, str, vargs) - : detail::vprint_mojibake(f, str, vargs); +template ::value)> +inline auto format_to_n(OutputIt out, size_t n, format_string fmt, + const T&... args) -> format_to_n_result { + return vformat_to_n(out, n, fmt, make_format_args(args...)); } +/** Returns the number of chars in the output of ``format(fmt, args...)``. */ +template +inline auto formatted_size(format_string fmt, T&&... args) -> size_t { + auto buf = detail::counting_buffer<>(); + detail::vformat_to(buf, string_view(fmt), make_format_args(args...)); + return buf.count(); +} + +FMT_API void vprint(string_view, format_args); +FMT_API void vprint(std::FILE*, string_view, format_args); + /** \rst - Formats ``args`` according to specifications in ``str`` and writes the output + Formats ``args`` according to specifications in ``fmt`` and writes the output to ``stdout``. Strings are assumed to be in UTF-8 unless the ``FMT_UNICODE`` macro is set to 0. @@ -2978,10 +2942,28 @@ inline void print(std::FILE* f, format_string str, T&&... args) { \endrst */ template -inline void print(format_string str, T&&... args) { +inline void print(format_string fmt, T&&... args) { const auto& vargs = make_format_args(args...); - return detail::is_utf8() ? vprint(str, vargs) - : detail::vprint_mojibake(stdout, str, vargs); + return detail::is_utf8() ? vprint(fmt, vargs) + : detail::vprint_mojibake(stdout, fmt, vargs); +} + +/** + \rst + Formats ``args`` according to specifications in ``fmt`` and writes the + output to the file ``f``. Strings are assumed to be in UTF-8 unless the + ``FMT_UNICODE`` macro is set to 0. + + **Example**:: + + fmt::print(stderr, "Don't {}!", "panic"); + \endrst + */ +template +inline void print(std::FILE* f, format_string fmt, T&&... args) { + const auto& vargs = make_format_args(args...); + return detail::is_utf8() ? vprint(f, fmt, vargs) + : detail::vprint_mojibake(f, fmt, vargs); } FMT_MODULE_EXPORT_END diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 02a4e7c3..93b7a907 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -2575,14 +2575,14 @@ FMT_FUNC void report_system_error(int error_code, report_error(format_system_error, error_code, message); } -FMT_FUNC std::string detail::vformat(string_view format_str, format_args args) { - if (format_str.size() == 2 && equal2(format_str.data(), "{}")) { +FMT_FUNC std::string vformat(string_view fmt, format_args args) { + if (fmt.size() == 2 && detail::equal2(fmt.data(), "{}")) { auto arg = args.get(0); - if (!arg) error_handler().on_error("argument not found"); - return visit_format_arg(stringifier(), arg); + if (!arg) detail::error_handler().on_error("argument not found"); + return visit_format_arg(detail::stringifier(), arg); } memory_buffer buffer; - detail::vformat_to(buffer, format_str, args); + detail::vformat_to(buffer, fmt, args); return to_string(buffer); } diff --git a/include/fmt/format.h b/include/fmt/format.h index e887d850..669260eb 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -2573,7 +2573,8 @@ FMT_MODULE_EXPORT_END template void detail::vformat_to( - detail::buffer& buf, basic_string_view format_str, + detail::buffer>& buf, + basic_string_view format_str, basic_format_args>> args, detail::locale_ref loc) { using iterator = typename buffer_context::iterator; @@ -2621,6 +2622,14 @@ extern template int snprintf_float(long double value, FMT_MODULE_EXPORT_BEGIN +template +using format_context_t FMT_DEPRECATED_ALIAS = + basic_format_context; + +template +using format_args_t FMT_DEPRECATED_ALIAS = + basic_format_args>; + template , FMT_ENABLE_IF(detail::is_string::value)> inline void vformat_to( @@ -2639,18 +2648,61 @@ inline auto format_to(basic_memory_buffer& buf, const S& format_str, return detail::buffer_appender(buf); } -template -using format_context_t FMT_DEPRECATED_ALIAS = - basic_format_context; +template , + FMT_ENABLE_IF(detail::is_output_iterator::value && + !std::is_same::value)> +auto vformat_to(OutputIt out, const S& format_str, + basic_format_args>> args) + -> OutputIt { + decltype(detail::get_buffer(out)) buf(detail::get_buffer_init(out)); + detail::vformat_to(buf, to_string_view(format_str), args); + return detail::get_iterator(buf); +} -template -using format_args_t FMT_DEPRECATED_ALIAS = - basic_format_args>; +template , + FMT_ENABLE_IF(detail::is_output_iterator::value && + !std::is_same::value)> +inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt { + const auto& vargs = fmt::make_args_checked(fmt, args...); + return vformat_to(out, to_string_view(fmt), vargs); +} -template ::value), int>> -auto detail::vformat( - basic_string_view format_str, +template ::value && + !std::is_same::value)> +inline auto vformat_to_n( + OutputIt out, size_t n, basic_string_view format_str, basic_format_args>> args) + -> format_to_n_result { + detail::iterator_buffer buf(out, + n); + detail::vformat_to(buf, format_str, args); + return {buf.out(), buf.count()}; +} + +template , + FMT_ENABLE_IF(detail::is_output_iterator::value && + !std::is_same::value)> +inline auto format_to_n(OutputIt out, size_t n, const S& fmt, + const Args&... args) -> format_to_n_result { + const auto& vargs = fmt::make_args_checked(fmt, args...); + return vformat_to_n(out, n, to_string_view(fmt), vargs); +} + +template , + FMT_ENABLE_IF(!std::is_same::value)> +inline auto formatted_size(const S& fmt, Args&&... args) -> size_t { + detail::counting_buffer<> buf; + const auto& vargs = fmt::make_args_checked(fmt, args...); + detail::vformat_to(buf, to_string_view(fmt), vargs); + return buf.count(); +} + +template ::value)> +auto vformat(basic_string_view format_str, + basic_format_args>> args) -> std::basic_string { basic_memory_buffer buffer; detail::vformat_to(buffer, format_str, args); @@ -2661,10 +2713,9 @@ auto detail::vformat( // std::basic_string> to reduce the symbol size. template , FMT_ENABLE_IF(!std::is_same::value)> -FMT_INLINE auto format(const S& format_str, Args&&... args) - -> std::basic_string { +auto format(const S& format_str, Args&&... args) -> std::basic_string { const auto& vargs = fmt::make_args_checked(format_str, args...); - return detail::vformat(to_string_view(format_str), vargs); + return vformat(to_string_view(format_str), vargs); } FMT_MODULE_EXPORT_END diff --git a/include/fmt/os.h b/include/fmt/os.h index 1a8833de..1e078bd1 100644 --- a/include/fmt/os.h +++ b/include/fmt/os.h @@ -432,13 +432,12 @@ class ostream final : private detail::buffer { } /** - Formats ``args`` according to specifications in ``format_str`` and writes - the output to the file. + Formats ``args`` according to specifications in ``fmt`` and writes the + output to the file. */ - template - void print(const S& format_str, Args&&... args) { - format_to(detail::buffer_appender(*this), format_str, - std::forward(args)...); + template void print(format_string fmt, T&&... args) { + vformat_to(detail::buffer_appender(*this), fmt, + make_format_args(args...)); } };