Cleanup format API

This commit is contained in:
Victor Zverovich 2024-09-11 07:17:14 -07:00
parent ab44ee7521
commit 6f62db098a
5 changed files with 125 additions and 136 deletions

View File

@ -837,7 +837,7 @@ struct format_specs : basic_specs {
*/
template <typename Char = char> class parse_context {
private:
basic_string_view<Char> format_str_;
basic_string_view<Char> fmt_;
int next_arg_id_;
enum { use_constexpr_cast = !FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200 };
@ -848,22 +848,20 @@ template <typename Char = char> class parse_context {
using char_type = Char;
using iterator = const Char*;
explicit constexpr parse_context(basic_string_view<Char> format_str,
explicit constexpr parse_context(basic_string_view<Char> fmt,
int next_arg_id = 0)
: format_str_(format_str), next_arg_id_(next_arg_id) {}
: fmt_(fmt), next_arg_id_(next_arg_id) {}
/// Returns an iterator to the beginning of the format string range being
/// parsed.
constexpr auto begin() const noexcept -> iterator {
return format_str_.begin();
}
constexpr auto begin() const noexcept -> iterator { return fmt_.begin(); }
/// Returns an iterator past the end of the format string range being parsed.
constexpr auto end() const noexcept -> iterator { return format_str_.end(); }
constexpr auto end() const noexcept -> iterator { return fmt_.end(); }
/// Advances the begin iterator to `it`.
FMT_CONSTEXPR void advance_to(iterator it) {
format_str_.remove_prefix(detail::to_unsigned(it - begin()));
fmt_.remove_prefix(detail::to_unsigned(it - begin()));
}
/// Reports an error if using the manual argument indexing; otherwise returns
@ -1273,10 +1271,10 @@ class compile_parse_context : public parse_context<Char> {
using base = parse_context<Char>;
public:
explicit FMT_CONSTEXPR compile_parse_context(
basic_string_view<Char> format_str, int num_args, const type* types,
int next_arg_id = 0)
: base(format_str, next_arg_id), num_args_(num_args), types_(types) {}
explicit FMT_CONSTEXPR compile_parse_context(basic_string_view<Char> fmt,
int num_args, const type* types,
int next_arg_id = 0)
: base(fmt, next_arg_id), num_args_(num_args), types_(types) {}
constexpr auto num_args() const -> int { return num_args_; }
constexpr auto arg_type(int id) const -> type { return types_[id]; }

View File

@ -2133,7 +2133,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
detail::arg_ref<Char> width_ref_;
detail::arg_ref<Char> precision_ref_;
bool localized_ = false;
basic_string_view<Char> format_str_;
basic_string_view<Char> fmt_;
public:
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
@ -2159,7 +2159,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
++it;
}
end = detail::parse_chrono_format(it, end, checker);
format_str_ = {it, detail::to_unsigned(end - it)};
fmt_ = {it, detail::to_unsigned(end - it)};
return end;
}
@ -2169,7 +2169,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
auto specs = specs_;
auto precision = specs.precision;
specs.precision = -1;
auto begin = format_str_.begin(), end = format_str_.end();
auto begin = fmt_.begin(), end = fmt_.end();
// As a possible future optimization, we could avoid extra copying if width
// is not specified.
auto buf = basic_memory_buffer<Char>();
@ -2200,7 +2200,7 @@ template <typename Char> struct formatter<std::tm, Char> {
detail::arg_ref<Char> width_ref_;
protected:
basic_string_view<Char> format_str_;
basic_string_view<Char> fmt_;
template <typename Duration, typename FormatContext>
auto do_format(const std::tm& tm, FormatContext& ctx,
@ -2215,7 +2215,7 @@ template <typename Char> struct formatter<std::tm, Char> {
detail::get_locale loc(static_cast<bool>(loc_ref), loc_ref);
auto w =
detail::tm_writer<decltype(out), Char, Duration>(loc, out, tm, subsecs);
detail::parse_chrono_format(format_str_.begin(), format_str_.end(), w);
detail::parse_chrono_format(fmt_.begin(), fmt_.end(), w);
return detail::write(
ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
}
@ -2235,8 +2235,8 @@ template <typename Char> struct formatter<std::tm, Char> {
}
end = detail::parse_chrono_format(it, end, detail::tm_format_checker());
// Replace the default format_str only if the new spec is not empty.
if (end != it) format_str_ = {it, detail::to_unsigned(end - it)};
// Replace the default format string only if the new spec is not empty.
if (end != it) fmt_ = {it, detail::to_unsigned(end - it)};
return end;
}
@ -2250,7 +2250,7 @@ template <typename Char> struct formatter<std::tm, Char> {
template <typename Char, typename Duration>
struct formatter<sys_time<Duration>, Char> : formatter<std::tm, Char> {
FMT_CONSTEXPR formatter() {
this->format_str_ = detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>();
this->fmt_ = detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>();
}
template <typename FormatContext>
@ -2292,7 +2292,7 @@ struct formatter<utc_time<Duration>, Char>
template <typename Duration, typename Char>
struct formatter<local_time<Duration>, Char> : formatter<std::tm, Char> {
FMT_CONSTEXPR formatter() {
this->format_str_ = detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>();
this->fmt_ = detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>();
}
template <typename FormatContext>

View File

@ -964,6 +964,14 @@ class basic_memory_buffer : public detail::buffer<T> {
using memory_buffer = basic_memory_buffer<char>;
template <typename Char, size_t SIZE>
FMT_NODISCARD auto to_string(const basic_memory_buffer<Char, SIZE>& buf)
-> std::basic_string<Char> {
auto size = buf.size();
detail::assume(size < std::basic_string<Char>().max_size());
return std::basic_string<Char>(buf.data(), size);
}
// A writer to a buffered stream. It doesn't own the underlying stream.
class writer {
private:
@ -3880,11 +3888,39 @@ FMT_API void report_error(format_func func, int error_code,
template <typename T>
struct has_format_as
: bool_constant<!std::is_same<format_as_t<T>, void>::value> {};
FMT_BEGIN_EXPORT
#ifndef FMT_HEADER_ONLY
extern template FMT_API auto thousands_sep_impl<char>(locale_ref)
-> thousands_sep_result<char>;
extern template FMT_API auto thousands_sep_impl<wchar_t>(locale_ref)
-> thousands_sep_result<wchar_t>;
extern template FMT_API auto decimal_point_impl(locale_ref) -> char;
extern template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
#endif // FMT_HEADER_ONLY
FMT_END_EXPORT
template <typename T, typename Char, type TYPE>
template <typename FormatContext>
FMT_CONSTEXPR auto native_formatter<T, Char, TYPE>::format(
const T& val, FormatContext& ctx) const -> decltype(ctx.out()) {
if (!specs_.dynamic())
return write<Char>(ctx.out(), val, specs_, ctx.locale());
auto specs = format_specs(specs_);
handle_dynamic_spec(specs.dynamic_width(), specs.width, specs_.width_ref,
ctx);
handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
specs_.precision_ref, ctx);
return write<Char>(ctx.out(), val, specs, ctx.locale());
}
} // namespace detail
FMT_BEGIN_EXPORT
FMT_API auto vsystem_error(int error_code, string_view format_str,
format_args args) -> std::system_error;
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
@ -4196,80 +4232,6 @@ template <typename T, typename Char = char> struct nested_formatter {
}
};
/**
* Converts `value` to `std::string` using the default format for type `T`.
*
* **Example**:
*
* std::string answer = fmt::to_string(42);
*/
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value &&
!detail::has_format_as<T>::value)>
inline auto to_string(const T& value) -> std::string {
auto buffer = memory_buffer();
detail::write<char>(appender(buffer), value);
return {buffer.data(), buffer.size()};
}
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
FMT_NODISCARD inline auto to_string(T value) -> std::string {
// The buffer should be large enough to store the number including the sign
// or "false" for bool.
constexpr int max_size = detail::digits10<T>() + 2;
char buffer[max_size > 5 ? static_cast<unsigned>(max_size) : 5];
char* begin = buffer;
return std::string(begin, detail::write<char>(begin, value));
}
template <typename Char, size_t SIZE>
FMT_NODISCARD auto to_string(const basic_memory_buffer<Char, SIZE>& buf)
-> std::basic_string<Char> {
auto size = buf.size();
detail::assume(size < std::basic_string<Char>().max_size());
return std::basic_string<Char>(buf.data(), size);
}
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value &&
detail::has_format_as<T>::value)>
inline auto to_string(const T& value) -> std::string {
return to_string(format_as(value));
}
FMT_END_EXPORT
namespace detail {
FMT_BEGIN_EXPORT
#ifndef FMT_HEADER_ONLY
extern template FMT_API auto thousands_sep_impl<char>(locale_ref)
-> thousands_sep_result<char>;
extern template FMT_API auto thousands_sep_impl<wchar_t>(locale_ref)
-> thousands_sep_result<wchar_t>;
extern template FMT_API auto decimal_point_impl(locale_ref) -> char;
extern template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
#endif // FMT_HEADER_ONLY
FMT_END_EXPORT
template <typename T, typename Char, type TYPE>
template <typename FormatContext>
FMT_CONSTEXPR auto native_formatter<T, Char, TYPE>::format(
const T& val, FormatContext& ctx) const -> decltype(ctx.out()) {
if (!specs_.dynamic())
return write<Char>(ctx.out(), val, specs_, ctx.locale());
auto specs = format_specs(specs_);
handle_dynamic_spec(specs.dynamic_width(), specs.width, specs_.width_ref,
ctx);
handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
specs_.precision_ref, ctx);
return write<Char>(ctx.out(), val, specs, ctx.locale());
}
} // namespace detail
FMT_BEGIN_EXPORT
template <typename Char>
struct formatter<detail::float128, Char>
: detail::native_formatter<detail::float128, Char,
@ -4298,32 +4260,15 @@ constexpr auto operator""_a(const char* s, size_t) -> detail::udl_arg<char> {
} // namespace literals
#endif // FMT_USE_USER_LITERALS
FMT_API auto vformat(string_view fmt, format_args args) -> std::string;
/**
* Formats `args` according to specifications in `fmt` and returns the result
* as a string.
*
* **Example**:
*
* #include <fmt/format.h>
* std::string message = fmt::format("The answer is {}.", 42);
*/
template <typename... T>
FMT_NODISCARD FMT_INLINE auto format(format_string<T...> fmt, T&&... args)
-> std::string {
return vformat(fmt.str, vargs<T...>{{args...}});
}
template <typename Locale, FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
inline auto vformat(const Locale& loc, string_view fmt, format_args args)
auto vformat(const Locale& loc, string_view fmt, format_args args)
-> std::string {
return detail::vformat(loc, fmt, args);
}
template <typename Locale, typename... T,
FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
inline auto format(const Locale& loc, format_string<T...> fmt, T&&... args)
FMT_INLINE auto format(const Locale& loc, format_string<T...> fmt, T&&... args)
-> std::string {
return fmt::vformat(loc, fmt.str, vargs<T...>{{args...}});
}
@ -4343,7 +4288,7 @@ template <typename OutputIt, typename Locale, typename... T,
detail::is_locale<Locale>::value)>
FMT_INLINE auto format_to(OutputIt out, const Locale& loc,
format_string<T...> fmt, T&&... args) -> OutputIt {
return vformat_to(out, loc, fmt.str, vargs<T...>{{args...}});
return fmt::vformat_to(out, loc, fmt.str, vargs<T...>{{args...}});
}
template <typename Locale, typename... T,
@ -4357,6 +4302,54 @@ FMT_NODISCARD FMT_INLINE auto formatted_size(const Locale& loc,
return buf.count();
}
FMT_API auto vformat(string_view fmt, format_args args) -> std::string;
/**
* Formats `args` according to specifications in `fmt` and returns the result
* as a string.
*
* **Example**:
*
* #include <fmt/format.h>
* std::string message = fmt::format("The answer is {}.", 42);
*/
template <typename... T>
FMT_NODISCARD FMT_INLINE auto format(format_string<T...> fmt, T&&... args)
-> std::string {
return vformat(fmt.str, vargs<T...>{{args...}});
}
/**
* Converts `value` to `std::string` using the default format for type `T`.
*
* **Example**:
*
* std::string answer = fmt::to_string(42);
*/
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
FMT_NODISCARD auto to_string(T value) -> std::string {
// The buffer should be large enough to store the number including the sign
// or "false" for bool.
constexpr int max_size = detail::digits10<T>() + 2;
char buffer[max_size > 5 ? static_cast<unsigned>(max_size) : 5];
char* begin = buffer;
return std::string(buffer, detail::write<char>(begin, value));
}
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value &&
!detail::has_format_as<T>::value)>
FMT_NODISCARD auto to_string(const T& value) -> std::string {
auto buffer = memory_buffer();
detail::write<char>(appender(buffer), value);
return {buffer.data(), buffer.size()};
}
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value &&
detail::has_format_as<T>::value)>
FMT_NODISCARD auto to_string(const T& value) -> std::string {
return to_string(format_as(value));
}
FMT_END_EXPORT
FMT_END_NAMESPACE

View File

@ -118,7 +118,7 @@ FMT_API void format_windows_error(buffer<char>& out, int error_code,
const char* message) noexcept;
}
FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
FMT_API std::system_error vwindows_error(int error_code, string_view fmt,
format_args args);
/**
@ -164,8 +164,8 @@ inline auto system_category() noexcept -> const std::error_category& {
// std::system is not available on some platforms such as iOS (#2248).
#ifdef __OSX__
template <typename S, typename... Args, typename Char = char_t<S>>
void say(const S& format_str, Args&&... args) {
std::system(format("say \"{}\"", format(format_str, args...)).c_str());
void say(const S& fmt, Args&&... args) {
std::system(format("say \"{}\"", format(fmt, args...)).c_str());
}
#endif

View File

@ -162,11 +162,11 @@ auto join(const std::tuple<T...>& tuple, basic_string_view<wchar_t> sep)
}
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
auto vformat(basic_string_view<Char> format_str,
auto vformat(basic_string_view<Char> fmt,
typename detail::vformat_args<Char>::type args)
-> std::basic_string<Char> {
auto buf = basic_memory_buffer<Char>();
detail::vformat_to(buf, format_str, args);
detail::vformat_to(buf, fmt, args);
return to_string(buf);
}
@ -188,8 +188,8 @@ template <typename S, typename... T,
typename Char = detail::format_string_char_t<S>,
FMT_ENABLE_IF(!std::is_same<Char, char>::value &&
!std::is_same<Char, wchar_t>::value)>
auto format(const S& format_str, T&&... args) -> std::basic_string<Char> {
return vformat(detail::to_string_view(format_str),
auto format(const S& fmt, T&&... args) -> std::basic_string<Char> {
return vformat(detail::to_string_view(fmt),
fmt::make_format_args<buffered_context<Char>>(args...));
}
@ -210,9 +210,9 @@ template <typename Locale, typename S, typename... T,
typename Char = detail::format_string_char_t<S>,
FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
detail::is_exotic_char<Char>::value)>
inline auto format(const Locale& loc, const S& format_str, T&&... args)
inline auto format(const Locale& loc, const S& fmt, T&&... args)
-> std::basic_string<Char> {
return vformat(loc, detail::to_string_view(format_str),
return vformat(loc, detail::to_string_view(fmt),
fmt::make_format_args<buffered_context<Char>>(args...));
}
@ -220,10 +220,10 @@ template <typename OutputIt, typename S,
typename Char = detail::format_string_char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)>
auto vformat_to(OutputIt out, const S& format_str,
auto vformat_to(OutputIt out, const S& fmt,
typename detail::vformat_args<Char>::type args) -> OutputIt {
auto&& buf = detail::get_buffer<Char>(out);
detail::vformat_to(buf, detail::to_string_view(format_str), args);
detail::vformat_to(buf, detail::to_string_view(fmt), args);
return detail::get_iterator(buf, out);
}
@ -242,12 +242,11 @@ template <typename Locale, typename S, typename OutputIt, typename... Args,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_locale<Locale>::value&&
detail::is_exotic_char<Char>::value)>
inline auto vformat_to(OutputIt out, const Locale& loc, const S& format_str,
inline auto vformat_to(OutputIt out, const Locale& loc, const S& fmt,
typename detail::vformat_args<Char>::type args)
-> OutputIt {
auto&& buf = detail::get_buffer<Char>(out);
vformat_to(buf, detail::to_string_view(format_str), args,
detail::locale_ref(loc));
vformat_to(buf, detail::to_string_view(fmt), args, detail::locale_ref(loc));
return detail::get_iterator(buf, out);
}
@ -256,23 +255,22 @@ template <typename OutputIt, typename Locale, typename S, typename... T,
bool enable = detail::is_output_iterator<OutputIt, Char>::value &&
detail::is_locale<Locale>::value &&
detail::is_exotic_char<Char>::value>
inline auto format_to(OutputIt out, const Locale& loc, const S& format_str,
inline auto format_to(OutputIt out, const Locale& loc, const S& fmt,
T&&... args) ->
typename std::enable_if<enable, OutputIt>::type {
return vformat_to(out, loc, detail::to_string_view(format_str),
return vformat_to(out, loc, detail::to_string_view(fmt),
fmt::make_format_args<buffered_context<Char>>(args...));
}
template <typename OutputIt, typename Char, typename... Args,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
detail::is_exotic_char<Char>::value)>
inline auto vformat_to_n(OutputIt out, size_t n,
basic_string_view<Char> format_str,
inline auto vformat_to_n(OutputIt out, size_t n, basic_string_view<Char> fmt,
typename detail::vformat_args<Char>::type args)
-> format_to_n_result<OutputIt> {
using traits = detail::fixed_buffer_traits;
auto buf = detail::iterator_buffer<OutputIt, Char, traits>(out, n);
detail::vformat_to(buf, format_str, args);
detail::vformat_to(buf, fmt, args);
return {buf.out(), buf.count()};
}