From ab8f9d5b0802fe139ce3214475e7517f1c985e9a Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 11 Sep 2024 07:48:43 -0700 Subject: [PATCH] Cleanup format API --- include/fmt/format.h | 231 +++++++++++++++++++++---------------------- include/fmt/printf.h | 2 +- include/fmt/xchar.h | 4 +- 3 files changed, 115 insertions(+), 122 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index e442594d..5412b3d8 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -964,12 +964,12 @@ class basic_memory_buffer : public detail::buffer { using memory_buffer = basic_memory_buffer; -template -FMT_NODISCARD auto to_string(const basic_memory_buffer& buf) - -> std::basic_string { +template +FMT_NODISCARD auto to_string(basic_memory_buffer& buf) + -> std::string { auto size = buf.size(); - detail::assume(size < std::basic_string().max_size()); - return std::basic_string(buf.data(), size); + detail::assume(size < std::string().max_size()); + return {buf.data(), size}; } // A writer to a buffered stream. It doesn't own the underlying stream. @@ -1020,7 +1020,7 @@ FMT_CONSTEXPR auto make_arg(T& val) -> basic_format_arg { } FMT_API auto write_console(int fd, string_view text) -> bool; -FMT_API void print(std::FILE*, string_view); +FMT_API void print(FILE*, string_view); } // namespace detail FMT_BEGIN_EXPORT @@ -3868,14 +3868,6 @@ void vformat_to(buffer& buf, basic_string_view fmt, fmt, format_handler{parse_context(fmt), {out, args, loc}}); } -template -auto vformat(const Locale& loc, string_view fmt, format_args args) - -> std::string { - auto buf = memory_buffer(); - detail::vformat_to(buf, fmt, args, detail::locale_ref(loc)); - return {buf.data(), buf.size()}; -} - using format_func = void (*)(detail::buffer&, int, const char*); FMT_API void format_error_code(buffer& out, int error_code, @@ -3915,112 +3907,8 @@ FMT_CONSTEXPR auto native_formatter::format( specs_.precision_ref, ctx); return write(ctx.out(), val, specs, ctx.locale()); } - } // namespace detail -FMT_BEGIN_EXPORT -FMT_API auto vsystem_error(int error_code, string_view fmt, format_args args) - -> std::system_error; - -/** - * Constructs `std::system_error` with a message formatted with - * `fmt::format(fmt, args...)`. - * `error_code` is a system error code as given by `errno`. - * - * **Example**: - * - * // This throws std::system_error with the description - * // cannot open file 'madeup': No such file or directory - * // or similar (system message may vary). - * const char* filename = "madeup"; - * std::FILE* file = std::fopen(filename, "r"); - * if (!file) - * throw fmt::system_error(errno, "cannot open file '{}'", filename); - */ -template -auto system_error(int error_code, format_string fmt, T&&... args) - -> std::system_error { - return vsystem_error(error_code, fmt.str, vargs{{args...}}); -} - -/** - * Formats an error message for an error returned by an operating system or a - * language runtime, for example a file opening error, and writes it to `out`. - * The format is the same as the one used by `std::system_error(ec, message)` - * where `ec` is `std::error_code(error_code, std::generic_category())`. - * It is implementation-defined but normally looks like: - * - * : - * - * where `` is the passed message and `` is the system - * message corresponding to the error code. - * `error_code` is a system error code as given by `errno`. - */ -FMT_API void format_system_error(detail::buffer& out, int error_code, - const char* message) noexcept; - -// Reports a system error without throwing an exception. -// Can be used to report errors from destructors. -FMT_API void report_system_error(int error_code, const char* message) noexcept; - -/// A fast integer formatter. -class format_int { - private: - // Buffer should be large enough to hold all digits (digits10 + 1), - // a sign and a null character. - enum { buffer_size = std::numeric_limits::digits10 + 3 }; - mutable char buffer_[buffer_size]; - char* str_; - - template - FMT_CONSTEXPR20 auto format_unsigned(UInt value) -> char* { - auto n = static_cast>(value); - return detail::do_format_decimal(buffer_, n, buffer_size - 1); - } - - template - FMT_CONSTEXPR20 auto format_signed(Int value) -> char* { - auto abs_value = static_cast>(value); - bool negative = value < 0; - if (negative) abs_value = 0 - abs_value; - auto begin = format_unsigned(abs_value); - if (negative) *--begin = '-'; - return begin; - } - - public: - explicit FMT_CONSTEXPR20 format_int(int value) : str_(format_signed(value)) {} - explicit FMT_CONSTEXPR20 format_int(long value) - : str_(format_signed(value)) {} - explicit FMT_CONSTEXPR20 format_int(long long value) - : str_(format_signed(value)) {} - explicit FMT_CONSTEXPR20 format_int(unsigned value) - : str_(format_unsigned(value)) {} - explicit FMT_CONSTEXPR20 format_int(unsigned long value) - : str_(format_unsigned(value)) {} - explicit FMT_CONSTEXPR20 format_int(unsigned long long value) - : str_(format_unsigned(value)) {} - - /// Returns the number of characters written to the output buffer. - FMT_CONSTEXPR20 auto size() const -> size_t { - return detail::to_unsigned(buffer_ - str_ + buffer_size - 1); - } - - /// Returns a pointer to the output buffer content. No terminating null - /// character is appended. - FMT_CONSTEXPR20 auto data() const -> const char* { return str_; } - - /// Returns a pointer to the output buffer content with terminating null - /// character appended. - FMT_CONSTEXPR20 auto c_str() const -> const char* { - buffer_[buffer_size - 1] = '\0'; - return str_; - } - - /// Returns the content of the output buffer as an `std::string`. - auto str() const -> std::string { return std::string(str_, size()); } -}; - template struct formatter::value>> : formatter, Char> { @@ -4260,10 +4148,115 @@ constexpr auto operator""_a(const char* s, size_t) -> detail::udl_arg { } // namespace literals #endif // FMT_USE_USER_LITERALS +/// A fast integer formatter. +class format_int { + private: + // Buffer should be large enough to hold all digits (digits10 + 1), + // a sign and a null character. + enum { buffer_size = std::numeric_limits::digits10 + 3 }; + mutable char buffer_[buffer_size]; + char* str_; + + template + FMT_CONSTEXPR20 auto format_unsigned(UInt value) -> char* { + auto n = static_cast>(value); + return detail::do_format_decimal(buffer_, n, buffer_size - 1); + } + + template + FMT_CONSTEXPR20 auto format_signed(Int value) -> char* { + auto abs_value = static_cast>(value); + bool negative = value < 0; + if (negative) abs_value = 0 - abs_value; + auto begin = format_unsigned(abs_value); + if (negative) *--begin = '-'; + return begin; + } + + public: + explicit FMT_CONSTEXPR20 format_int(int value) : str_(format_signed(value)) {} + explicit FMT_CONSTEXPR20 format_int(long value) + : str_(format_signed(value)) {} + explicit FMT_CONSTEXPR20 format_int(long long value) + : str_(format_signed(value)) {} + explicit FMT_CONSTEXPR20 format_int(unsigned value) + : str_(format_unsigned(value)) {} + explicit FMT_CONSTEXPR20 format_int(unsigned long value) + : str_(format_unsigned(value)) {} + explicit FMT_CONSTEXPR20 format_int(unsigned long long value) + : str_(format_unsigned(value)) {} + + /// Returns the number of characters written to the output buffer. + FMT_CONSTEXPR20 auto size() const -> size_t { + return detail::to_unsigned(buffer_ - str_ + buffer_size - 1); + } + + /// Returns a pointer to the output buffer content. No terminating null + /// character is appended. + FMT_CONSTEXPR20 auto data() const -> const char* { return str_; } + + /// Returns a pointer to the output buffer content with terminating null + /// character appended. + FMT_CONSTEXPR20 auto c_str() const -> const char* { + buffer_[buffer_size - 1] = '\0'; + return str_; + } + + /// Returns the content of the output buffer as an `std::string`. + auto str() const -> std::string { return std::string(str_, size()); } +}; + +FMT_BEGIN_EXPORT +FMT_API auto vsystem_error(int error_code, string_view fmt, format_args args) + -> std::system_error; + +/** + * Constructs `std::system_error` with a message formatted with + * `fmt::format(fmt, args...)`. + * `error_code` is a system error code as given by `errno`. + * + * **Example**: + * + * // This throws std::system_error with the description + * // cannot open file 'madeup': No such file or directory + * // or similar (system message may vary). + * const char* filename = "madeup"; + * FILE* file = fopen(filename, "r"); + * if (!file) + * throw fmt::system_error(errno, "cannot open file '{}'", filename); + */ +template +auto system_error(int error_code, format_string fmt, T&&... args) + -> std::system_error { + return vsystem_error(error_code, fmt.str, vargs{{args...}}); +} + +/** + * Formats an error message for an error returned by an operating system or a + * language runtime, for example a file opening error, and writes it to `out`. + * The format is the same as the one used by `std::system_error(ec, message)` + * where `ec` is `std::error_code(error_code, std::generic_category())`. + * It is implementation-defined but normally looks like: + * + * : + * + * where `` is the passed message and `` is the system + * message corresponding to the error code. + * `error_code` is a system error code as given by `errno`. + */ +FMT_API void format_system_error(detail::buffer& out, int error_code, + const char* message) noexcept; + +// Reports a system error without throwing an exception. +// Can be used to report errors from destructors. +FMT_API void report_system_error(int error_code, const char* message) noexcept; + template ::value)> auto vformat(const Locale& loc, string_view fmt, format_args args) -> std::string { - return detail::vformat(loc, fmt, args); + auto buf = memory_buffer(); + detail::vformat_to(buf, fmt, args, detail::locale_ref(loc)); + return {buf.data(), buf.size()}; } template fmt, -> std::basic_string { auto buf = basic_memory_buffer(); detail::vprintf(buf, fmt, args); - return to_string(buf); + return {buf.data(), buf.size()}; } /** diff --git a/include/fmt/xchar.h b/include/fmt/xchar.h index 07599eb1..fcbf1457 100644 --- a/include/fmt/xchar.h +++ b/include/fmt/xchar.h @@ -167,7 +167,7 @@ auto vformat(basic_string_view fmt, -> std::basic_string { auto buf = basic_memory_buffer(); detail::vformat_to(buf, fmt, args); - return to_string(buf); + return {buf.data(), buf.size()}; } template @@ -328,7 +328,7 @@ inline auto vformat(const text_style& ts, wstring_view fmt, wformat_args args) -> std::wstring { auto buf = wmemory_buffer(); detail::vformat_to(buf, ts, fmt, args); - return fmt::to_string(buf); + return {buf.data(), buf.size()}; } template