mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-30 10:47:35 +02:00
Separate argument parsing and formatting
This commit is contained in:
116
fmt/format.h
116
fmt/format.h
@ -3268,61 +3268,16 @@ struct precision_handler {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
template <typename Char>
|
||||
inline typename basic_context<Char>::format_arg
|
||||
basic_context<Char>::get_arg(
|
||||
basic_string_view<Char> name, const char *&error) {
|
||||
if (this->check_no_auto_index(error)) {
|
||||
map_.init(this->args());
|
||||
if (const format_arg *arg = map_.find(name))
|
||||
return *arg;
|
||||
error = "argument not found";
|
||||
}
|
||||
return format_arg();
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline typename basic_context<Char>::format_arg
|
||||
basic_context<Char>::parse_arg_id() {
|
||||
format_arg arg;
|
||||
auto &it = this->pos();
|
||||
if (!internal::is_name_start(*it)) {
|
||||
const char *error = 0;
|
||||
arg = *it < '0' || *it > '9' ?
|
||||
this->next_arg(error) :
|
||||
get_arg(internal::parse_nonnegative_int(it), error);
|
||||
if (error) {
|
||||
FMT_THROW(format_error(
|
||||
*it != '}' && *it != ':' ? "invalid format string" : error));
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
auto start = it;
|
||||
Char c;
|
||||
do {
|
||||
c = *++it;
|
||||
} while (internal::is_name_start(c) || ('0' <= c && c <= '9'));
|
||||
const char *error = 0;
|
||||
arg = get_arg(basic_string_view<Char>(
|
||||
internal::pointer_from(start), it - start), error);
|
||||
if (error)
|
||||
FMT_THROW(format_error(error));
|
||||
return arg;
|
||||
}
|
||||
|
||||
// Formats a single argument.
|
||||
template <typename ArgFormatter, typename Char, typename Context>
|
||||
void do_format_arg(basic_buffer<Char> &buffer, const basic_arg<Context>& arg,
|
||||
Context &ctx) {
|
||||
auto &it = ctx.pos();
|
||||
// Parses standard format specifiers.
|
||||
template <typename Context>
|
||||
basic_format_specs<typename Context::char_type>
|
||||
parse_format_specs(const basic_arg<Context>& arg, Context &ctx) {
|
||||
typedef typename Context::char_type Char;
|
||||
basic_format_specs<Char> spec;
|
||||
if (*it == ':') {
|
||||
if (visit(internal::custom_formatter<Char, Context>(buffer, ctx), arg))
|
||||
return;
|
||||
++it;
|
||||
// Parse fill and alignment.
|
||||
auto &it = ctx.pos();
|
||||
if (Char c = *it) {
|
||||
auto p = it + 1;
|
||||
spec.align_ = ALIGN_DEFAULT;
|
||||
@ -3429,6 +3384,20 @@ void do_format_arg(basic_buffer<Char> &buffer, const basic_arg<Context>& arg,
|
||||
// Parse type.
|
||||
if (*it != '}' && *it)
|
||||
spec.type_ = static_cast<char>(*it++);
|
||||
return spec;
|
||||
}
|
||||
|
||||
// Formats a single argument.
|
||||
template <typename ArgFormatter, typename Char, typename Context>
|
||||
void do_format_arg(basic_buffer<Char> &buffer, const basic_arg<Context>& arg,
|
||||
Context &ctx) {
|
||||
auto &it = ctx.pos();
|
||||
basic_format_specs<Char> spec;
|
||||
if (*it == ':') {
|
||||
if (visit(internal::custom_formatter<Char, Context>(buffer, ctx), arg))
|
||||
return;
|
||||
++it;
|
||||
spec = internal::parse_format_specs(arg, ctx);
|
||||
}
|
||||
|
||||
if (*it != '}')
|
||||
@ -3437,6 +3406,49 @@ void do_format_arg(basic_buffer<Char> &buffer, const basic_arg<Context>& arg,
|
||||
// Format argument.
|
||||
visit(ArgFormatter(buffer, ctx, spec), arg);
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
template <typename Char>
|
||||
inline typename basic_context<Char>::format_arg
|
||||
basic_context<Char>::get_arg(
|
||||
basic_string_view<Char> name, const char *&error) {
|
||||
if (this->check_no_auto_index(error)) {
|
||||
map_.init(this->args());
|
||||
if (const format_arg *arg = map_.find(name))
|
||||
return *arg;
|
||||
error = "argument not found";
|
||||
}
|
||||
return format_arg();
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline typename basic_context<Char>::format_arg
|
||||
basic_context<Char>::parse_arg_id() {
|
||||
format_arg arg;
|
||||
auto &it = this->pos();
|
||||
if (!internal::is_name_start(*it)) {
|
||||
const char *error = 0;
|
||||
arg = *it < '0' || *it > '9' ?
|
||||
this->next_arg(error) :
|
||||
get_arg(internal::parse_nonnegative_int(it), error);
|
||||
if (error) {
|
||||
FMT_THROW(format_error(
|
||||
*it != '}' && *it != ':' ? "invalid format string" : error));
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
auto start = it;
|
||||
Char c;
|
||||
do {
|
||||
c = *++it;
|
||||
} while (internal::is_name_start(c) || ('0' <= c && c <= '9'));
|
||||
const char *error = 0;
|
||||
arg = get_arg(basic_string_view<Char>(
|
||||
internal::pointer_from(start), it - start), error);
|
||||
if (error)
|
||||
FMT_THROW(format_error(error));
|
||||
return arg;
|
||||
}
|
||||
|
||||
/** Formats arguments and writes the output to the buffer. */
|
||||
template <typename ArgFormatter, typename Char, typename Context>
|
||||
@ -3457,7 +3469,7 @@ void vformat_to(basic_buffer<Char> &buffer, basic_string_view<Char> format_str,
|
||||
if (c == '}')
|
||||
FMT_THROW(format_error("unmatched '}' in format string"));
|
||||
buffer.append(pointer_from(start), pointer_from(it) - 1);
|
||||
do_format_arg<ArgFormatter>(buffer, ctx.parse_arg_id(), ctx);
|
||||
internal::do_format_arg<ArgFormatter>(buffer, ctx.parse_arg_id(), ctx);
|
||||
if (*it != '}')
|
||||
FMT_THROW(format_error(fmt::format("unknown format specifier")));
|
||||
start = ++it;
|
||||
|
@ -86,7 +86,7 @@ void format_value(basic_buffer<Char> &buf, const T &value,
|
||||
basic_memory_buffer<Char> buffer;
|
||||
internal::format_value(buffer, value);
|
||||
basic_string_view<Char> str(buffer.data(), buffer.size());
|
||||
do_format_arg< arg_formatter<Char> >(
|
||||
internal::do_format_arg< arg_formatter<Char> >(
|
||||
buf, internal::make_arg< basic_context<Char> >(str), ctx);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user