From 51f0178625183d57b9ddbccf9a50acbdfabc1cc2 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 22 May 2021 07:08:36 -0700 Subject: [PATCH] Cleanup the format API --- include/fmt/format.h | 278 +++++++++++++++++++++---------------------- 1 file changed, 135 insertions(+), 143 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index c152d88a..2a342e90 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -800,6 +800,27 @@ class FMT_API format_error : public std::runtime_error { ~format_error() FMT_NOEXCEPT FMT_OVERRIDE FMT_MSC_DEFAULT; }; +/** + \rst + Constructs a `~fmt::format_arg_store` object that contains references + to arguments and can be implicitly converted to `~fmt::format_args`. + If ``fmt`` is a compile-time string then `make_args_checked` checks + its validity at compile time. + \endrst + */ +template > +FMT_INLINE auto make_args_checked(const S& fmt, + const remove_reference_t&... args) + -> format_arg_store, remove_reference_t...> { + static_assert( + detail::count<( + std::is_base_of>::value && + std::is_reference::value)...>() == 0, + "passing views as lvalues is disallowed"); + detail::check_format_string(fmt); + return {args...}; +} + FMT_BEGIN_DETAIL_NAMESPACE inline void throw_format_error(const char* message) { @@ -2135,6 +2156,58 @@ constexpr auto compile_string_to_view(std_string_view s) */ #define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::compile_string, ) +#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +template struct fixed_string { + constexpr fixed_string(const Char (&str)[N]) { + copy_str(static_cast(str), str + N, + data); + } + Char data[N]{}; +}; +#endif + +#if FMT_USE_USER_DEFINED_LITERALS +template struct udl_formatter { + basic_string_view str; + + template + std::basic_string operator()(T&&... args) const { + return vformat(str, fmt::make_args_checked(str, args...)); + } +}; + +# if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +template Str> +struct statically_named_arg : view { + static constexpr auto name = Str.data; + + const T& value; + statically_named_arg(const T& v) : value(v) {} +}; + +template Str> +struct is_named_arg> : std::true_type {}; + +template Str> +struct is_statically_named_arg> + : std::true_type {}; + +template Str> struct udl_arg { + template auto operator=(T&& value) const { + return statically_named_arg(std::forward(value)); + } +}; +# else +template struct udl_arg { + const Char* str; + + template named_arg operator=(T&& value) const { + return {str, std::forward(value)}; + } +}; +# endif +#endif // FMT_USE_USER_DEFINED_LITERALS + using format_func = void (*)(detail::buffer&, int, const char*); FMT_API void format_error_code(buffer& out, int error_code, @@ -2167,7 +2240,7 @@ FMT_API std::system_error vsystem_error(int error_code, string_view format_str, template std::system_error system_error(int error_code, string_view message, const Args&... args) { - return vsystem_error(error_code, message, make_format_args(args...)); + return vsystem_error(error_code, message, fmt::make_format_args(args...)); } /** @@ -2611,11 +2684,12 @@ void detail::vformat_to( } #ifndef FMT_HEADER_ONLY -extern template void detail::vformat_to(detail::buffer&, string_view, - basic_format_args, - detail::locale_ref); namespace detail { +extern template void vformat_to(detail::buffer&, string_view, + basic_format_args, + detail::locale_ref); + extern template FMT_API std::string grouping_impl(locale_ref loc); extern template FMT_API std::string grouping_impl(locale_ref loc); extern template FMT_API char thousands_sep_impl(locale_ref loc); @@ -2627,8 +2701,7 @@ extern template int format_float(double value, int precision, extern template int format_float(long double value, int precision, float_specs specs, buffer& buf); -int snprintf_float(float value, int precision, float_specs specs, - buffer& buf) = delete; +void snprintf_float(float, int, float_specs, buffer&) = delete; extern template int snprintf_float(double value, int precision, float_specs specs, buffer& buf); @@ -2637,29 +2710,65 @@ extern template int snprintf_float(long double value, float_specs specs, buffer& buf); } // namespace detail -#endif +#endif // FMT_HEADER_ONLY FMT_MODULE_EXPORT_BEGIN +inline namespace literals { +/** + \rst + User-defined literal equivalent of :func:`fmt::arg`. + + **Example**:: + + using namespace fmt::literals; + fmt::print("Elapsed time: {s:.2f} seconds", "s"_a=1.23); + \endrst + */ +#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +template +constexpr auto operator""_a() + -> detail::udl_arg, + sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str> { + return {}; +} +#else +constexpr auto operator"" _a(const char* s, size_t) -> detail::udl_arg { + return {s}; +} +#endif /** \rst - Constructs a `~fmt::format_arg_store` object that contains references - to arguments and can be implicitly converted to `~fmt::format_args`. - If ``fmt`` is a compile-time string then `make_args_checked` checks - its validity at compile time. + User-defined literal equivalent of :func:`fmt::format`. + + **Example**:: + + using namespace fmt::literals; + std::string message = "The answer is {}"_format(42); \endrst */ -template > -FMT_INLINE auto make_args_checked(const S& fmt, - const remove_reference_t&... args) - -> format_arg_store, remove_reference_t...> { - static_assert( - detail::count<( - std::is_base_of>::value && - std::is_reference::value)...>() == 0, - "passing views as lvalues is disallowed"); - detail::check_format_string(fmt); - return {args...}; +constexpr auto operator"" _format(const char* s, size_t n) + -> detail::udl_formatter { + return {{s, n}}; +} +} // namespace literals + +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); + return to_string(buffer); +} + +// Pass char_t as a default template parameter instead of using +// std::basic_string> to reduce the symbol size. +template , + FMT_ENABLE_IF(!std::is_same::value)> +auto format(const S& format_str, Args&&... args) -> std::basic_string { + const auto& vargs = fmt::make_args_checked(format_str, args...); + return vformat(to_string_view(format_str), vargs); } template , @@ -2731,126 +2840,13 @@ inline auto formatted_size(const S& fmt, Args&&... args) -> size_t { 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); - return to_string(buffer); -} - -// Pass char_t as a default template parameter instead of using -// std::basic_string> to reduce the symbol size. -template , - FMT_ENABLE_IF(!std::is_same::value)> -auto format(const S& format_str, Args&&... args) -> std::basic_string { - const auto& vargs = fmt::make_args_checked(format_str, args...); - return vformat(to_string_view(format_str), vargs); -} FMT_MODULE_EXPORT_END - -#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS -namespace detail { -template struct fixed_string { - constexpr fixed_string(const Char (&str)[N]) { - copy_str(static_cast(str), str + N, - data); - } - Char data[N]{}; -}; -} // namespace detail -#endif - -#if FMT_USE_USER_DEFINED_LITERALS -namespace detail { -template struct udl_formatter { - basic_string_view str; - - template - std::basic_string operator()(T&&... args) const { - return vformat(str, fmt::make_args_checked(str, args...)); - } -}; - -# if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS -template Str> -struct statically_named_arg : view { - static constexpr auto name = Str.data; - - const T& value; - statically_named_arg(const T& v) : value(v) {} -}; - -template Str> -struct is_named_arg> : std::true_type {}; - -template Str> -struct is_statically_named_arg> - : std::true_type {}; - -template Str> struct udl_arg { - template auto operator=(T&& value) const { - return statically_named_arg(std::forward(value)); - } -}; -# else -template struct udl_arg { - const Char* str; - - template named_arg operator=(T&& value) const { - return {str, std::forward(value)}; - } -}; -# endif -} // namespace detail -FMT_MODULE_EXPORT_BEGIN - -inline namespace literals { -/** - \rst - User-defined literal equivalent of :func:`fmt::format`. - - **Example**:: - - using namespace fmt::literals; - std::string message = "The answer is {}"_format(42); - \endrst - */ -constexpr auto operator"" _format(const char* s, size_t n) - -> detail::udl_formatter { - return {{s, n}}; -} - -/** - \rst - User-defined literal equivalent of :func:`fmt::arg`. - - **Example**:: - - using namespace fmt::literals; - fmt::print("Elapsed time: {s:.2f} seconds", "s"_a=1.23); - \endrst - */ -# if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS -template -constexpr detail::udl_arg, - sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str> -operator""_a() { - return {}; -} -# else -constexpr detail::udl_arg operator"" _a(const char* s, size_t) { - return {s}; -} -# endif -} // namespace literals - -FMT_MODULE_EXPORT_END -#endif // FMT_USE_USER_DEFINED_LITERALS FMT_END_NAMESPACE +#ifdef FMT_DEPRECATED_WCHAR +# include "wchar.h" +#endif + #ifdef FMT_HEADER_ONLY # define FMT_FUNC inline # include "format-inl.h" @@ -2858,8 +2854,4 @@ FMT_END_NAMESPACE # define FMT_FUNC #endif -#ifdef FMT_DEPRECATED_WCHAR -# include "wchar.h" -#endif - #endif // FMT_FORMAT_H_