mirror of
https://github.com/fmtlib/fmt.git
synced 2024-11-22 10:30:05 +00:00
Return iterator from the format method
This commit is contained in:
parent
67928eae28
commit
91ee9c9acd
@ -568,8 +568,8 @@ class value {
|
||||
// iostreams.
|
||||
template <typename T>
|
||||
void set_pointer(T *p) {
|
||||
using type = typename std::remove_const<T>::type;
|
||||
static_assert(std::is_same<type, void>::value,
|
||||
using nonconst_type = typename std::remove_const<T>::type;
|
||||
static_assert(std::is_same<nonconst_type, void>::value,
|
||||
"formatting of non-void pointers is disallowed");
|
||||
set<POINTER>(pointer, p);
|
||||
}
|
||||
@ -583,7 +583,7 @@ class value {
|
||||
typename Context::template formatter_type<T> f;
|
||||
auto &&parse_ctx = ctx.parse_context();
|
||||
parse_ctx.advance_to(f.parse(parse_ctx));
|
||||
f.format(*static_cast<const T*>(arg), ctx);
|
||||
ctx.advance_to(f.format(*static_cast<const T*>(arg), ctx));
|
||||
}
|
||||
};
|
||||
|
||||
@ -710,6 +710,7 @@ inline typename std::enable_if<!IS_PACKED, basic_arg<Context>>::type
|
||||
return make_arg<Context>(value);
|
||||
}
|
||||
|
||||
// A map from argument names to their values for named arguments.
|
||||
template <typename Context>
|
||||
class arg_map {
|
||||
private:
|
||||
@ -748,9 +749,13 @@ class arg_map {
|
||||
|
||||
template <typename Range, typename Context>
|
||||
class context_base {
|
||||
public:
|
||||
using iterator = decltype(std::declval<Range>().begin());
|
||||
|
||||
private:
|
||||
basic_parse_context<typename Range::value_type> parse_context_;
|
||||
Range range_;
|
||||
iterator out_;
|
||||
basic_format_args<Context> args_;
|
||||
|
||||
protected:
|
||||
@ -790,6 +795,12 @@ class context_base {
|
||||
void on_error(const char *message) { parse_context_.on_error(message); }
|
||||
|
||||
Range range() { return range_; }
|
||||
|
||||
// Returns an iterator to the beginning of the output range.
|
||||
iterator begin() { return out_; }
|
||||
|
||||
// Advances the begin iterator to ``it``.
|
||||
void advance_to(iterator it) { out_ = it; }
|
||||
};
|
||||
|
||||
// A range that can grow dynamically.
|
||||
@ -833,6 +844,8 @@ class basic_context :
|
||||
template <typename T>
|
||||
using formatter_type = formatter<T, char_type>;
|
||||
|
||||
using range_type = Range;
|
||||
|
||||
private:
|
||||
internal::arg_map<basic_context> map_;
|
||||
|
||||
@ -843,6 +856,8 @@ class basic_context :
|
||||
using base::get_arg;
|
||||
|
||||
public:
|
||||
using typename base::iterator;
|
||||
|
||||
/**
|
||||
\rst
|
||||
Constructs a ``basic_context`` object. References to the arguments are
|
||||
@ -858,7 +873,7 @@ class basic_context :
|
||||
}
|
||||
format_arg get_arg(unsigned arg_id) { return this->do_get_arg(arg_id); }
|
||||
|
||||
// Checks if manual indexing is used and returns the argument with
|
||||
// Checks if manual indexing is used and returns the argument with the
|
||||
// specified name.
|
||||
format_arg get_arg(basic_string_view<char_type> name);
|
||||
};
|
||||
@ -878,7 +893,7 @@ class arg_store {
|
||||
IS_PACKED, internal::value<Context>, basic_arg<Context>>::type;
|
||||
|
||||
// If the arguments are not packed, add one more element to mark the end.
|
||||
value_type data_[NUM_ARGS + (IS_PACKED ? 0 : 1)];
|
||||
value_type data_[NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1)];
|
||||
|
||||
public:
|
||||
static const uint64_t TYPES = IS_PACKED ?
|
||||
@ -984,6 +999,8 @@ struct named_arg_base {
|
||||
// Serialized value<context>.
|
||||
mutable char data[sizeof(basic_arg<context>)];
|
||||
|
||||
named_arg_base(basic_string_view<Char> name) : name(name) {}
|
||||
|
||||
template <typename Context>
|
||||
basic_arg<Context> deserialize() const {
|
||||
basic_arg<Context> arg;
|
||||
@ -997,7 +1014,7 @@ struct named_arg : named_arg_base<Char> {
|
||||
const T &value;
|
||||
|
||||
named_arg(basic_string_view<Char> name, const T &val)
|
||||
: named_arg_base<Char>{name}, value(val) {}
|
||||
: named_arg_base<Char>(name), value(val) {}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -2789,14 +2789,16 @@ struct formatter<
|
||||
return pointer_from(it);
|
||||
}
|
||||
|
||||
template <typename Range>
|
||||
void format(const T &val, basic_context<Range> &ctx) {
|
||||
template <typename FormatContext>
|
||||
typename FormatContext::iterator format(const T &val, FormatContext &ctx) {
|
||||
internal::handle_dynamic_spec<internal::width_checker>(
|
||||
specs_.width_, specs_.width_ref, ctx);
|
||||
internal::handle_dynamic_spec<internal::precision_checker>(
|
||||
specs_.precision_, specs_.precision_ref, ctx);
|
||||
visit(arg_formatter<Range>(ctx.range(), ctx, specs_),
|
||||
internal::make_arg<basic_context<Range>>(val));
|
||||
using range = typename FormatContext::range_type;
|
||||
visit(arg_formatter<range>(ctx.range(), ctx, specs_),
|
||||
internal::make_arg<FormatContext>(val));
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
private:
|
||||
@ -2834,8 +2836,8 @@ struct dynamic_formatter {
|
||||
return pointer_from(it);
|
||||
}
|
||||
|
||||
template <typename Range, typename T>
|
||||
void format(const T &val, basic_context<Range> &ctx) {
|
||||
template <typename T, typename FormatContext>
|
||||
auto format(const T &val, FormatContext &ctx) -> decltype(ctx.begin()) {
|
||||
handle_specs(ctx);
|
||||
struct null_handler : internal::error_handler {
|
||||
void on_align(alignment) {}
|
||||
@ -2861,8 +2863,10 @@ struct dynamic_formatter {
|
||||
}
|
||||
if (specs_.precision_ != -1)
|
||||
checker.end_precision();
|
||||
visit(arg_formatter<Range>(ctx.range(), ctx, specs_),
|
||||
internal::make_arg<basic_context<Range>>(val));
|
||||
using range = typename FormatContext::range_type;
|
||||
visit(arg_formatter<range>(ctx.range(), ctx, specs_),
|
||||
internal::make_arg<FormatContext>(val));
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -103,11 +103,12 @@ struct formatter<T, Char,
|
||||
: formatter<basic_string_view<Char>, Char> {
|
||||
|
||||
template <typename Context>
|
||||
void format(const T &value, Context &ctx) {
|
||||
auto format(const T &value, Context &ctx) -> decltype(ctx.begin()) {
|
||||
basic_memory_buffer<Char> buffer;
|
||||
internal::format_value(buffer, value);
|
||||
basic_string_view<Char> str(buffer.data(), buffer.size());
|
||||
formatter<basic_string_view<Char>, Char>::format(str, ctx);
|
||||
return ctx.begin();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -285,11 +285,12 @@ class printf_arg_formatter : public internal::arg_formatter_base<Range> {
|
||||
template <typename T>
|
||||
struct printf_formatter {
|
||||
template <typename ParseContext>
|
||||
auto parse(ParseContext& ctx) { return ctx.begin(); }
|
||||
auto parse(ParseContext &ctx) { return ctx.begin(); }
|
||||
|
||||
template <typename Range>
|
||||
void format(const T &value, basic_printf_context<Range> &ctx) {
|
||||
template <typename FormatContext>
|
||||
auto format(const T &value, FormatContext &ctx) -> decltype(ctx.begin()) {
|
||||
internal::format_value(ctx.range().container(), value);
|
||||
return ctx.begin();
|
||||
}
|
||||
};
|
||||
|
||||
@ -306,8 +307,8 @@ class basic_printf_context :
|
||||
using formatter_type = printf_formatter<T>;
|
||||
|
||||
private:
|
||||
typedef internal::context_base<Range, basic_printf_context> Base;
|
||||
using format_arg = typename Base::format_arg;
|
||||
using base = internal::context_base<Range, basic_printf_context>;
|
||||
using format_arg = typename base::format_arg;
|
||||
using format_specs = basic_format_specs<char_type>;
|
||||
using iterator = internal::null_terminating_iterator<char_type>;
|
||||
|
||||
@ -332,10 +333,12 @@ class basic_printf_context :
|
||||
*/
|
||||
basic_printf_context(Range range, basic_string_view<char_type> format_str,
|
||||
basic_format_args<basic_printf_context> args)
|
||||
: Base(range, format_str, args) {}
|
||||
: base(range, format_str, args) {}
|
||||
|
||||
using Base::parse_context;
|
||||
using Base::range;
|
||||
using base::parse_context;
|
||||
using base::range;
|
||||
using base::begin;
|
||||
using base::advance_to;
|
||||
|
||||
/** Formats stored arguments and writes the output to the range. */
|
||||
FMT_API void format();
|
||||
@ -374,7 +377,7 @@ typename basic_printf_context<Range, AF>::format_arg
|
||||
(void)it;
|
||||
if (arg_index == std::numeric_limits<unsigned>::max())
|
||||
return this->do_get_arg(this->parse_context().next_arg_id());
|
||||
return Base::get_arg(arg_index - 1);
|
||||
return base::get_arg(arg_index - 1);
|
||||
}
|
||||
|
||||
template <typename Range, typename AF>
|
||||
|
@ -30,7 +30,7 @@ struct formatter<std::tm> {
|
||||
return pointer_from(end);
|
||||
}
|
||||
|
||||
void format(const std::tm &tm, context &ctx) {
|
||||
auto format(const std::tm &tm, context &ctx) -> decltype(ctx.begin()) {
|
||||
buffer &buf = ctx.range().container();
|
||||
std::size_t start = buf.size();
|
||||
for (;;) {
|
||||
@ -50,6 +50,7 @@ struct formatter<std::tm> {
|
||||
const std::size_t MIN_GROWTH = 10;
|
||||
buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
|
||||
}
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
memory_buffer tm_format;
|
||||
|
@ -1223,8 +1223,9 @@ struct formatter<Date> {
|
||||
return it;
|
||||
}
|
||||
|
||||
void format(const Date &d, context &ctx) {
|
||||
auto format(const Date &d, context &ctx) {
|
||||
format_range(ctx.range(), "{}-{}-{}", d.year(), d.month(), d.day());
|
||||
return ctx.begin();
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -1240,8 +1241,8 @@ class Answer {};
|
||||
namespace fmt {
|
||||
template <>
|
||||
struct formatter<Answer> : formatter<int> {
|
||||
void format(Answer, fmt::context &ctx) {
|
||||
formatter<int>::format(42, ctx);
|
||||
auto format(Answer, fmt::context &ctx) {
|
||||
return formatter<int>::format(42, ctx);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -1534,11 +1535,10 @@ struct variant {
|
||||
namespace fmt {
|
||||
template <>
|
||||
struct formatter<variant> : dynamic_formatter<> {
|
||||
void format(variant value, context& ctx) {
|
||||
auto format(variant value, context& ctx) {
|
||||
if (value.type == variant::INT)
|
||||
dynamic_formatter::format(42, ctx);
|
||||
else
|
||||
dynamic_formatter::format("foo", ctx);
|
||||
return dynamic_formatter::format(42, ctx);
|
||||
return dynamic_formatter::format("foo", ctx);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -83,9 +83,9 @@ struct formatter<Test, Char> {
|
||||
|
||||
using range = fmt::internal::dynamic_range<basic_buffer<Char>>;
|
||||
|
||||
void format(Test, basic_context<range> &ctx) {
|
||||
auto format(Test, basic_context<range> &ctx) -> decltype(ctx.begin()) {
|
||||
const Char *test = "test";
|
||||
ctx.range().container().append(test, test + std::strlen(test));
|
||||
return std::copy_n(test, std::strlen(test), ctx.begin());
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -434,7 +434,7 @@ TEST(UtilTest, FormatArgs) {
|
||||
EXPECT_FALSE(args[1]);
|
||||
}
|
||||
|
||||
struct CustomContext {
|
||||
struct custom_context {
|
||||
using char_type = char;
|
||||
|
||||
template <typename T>
|
||||
@ -444,20 +444,22 @@ struct CustomContext {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
void format(const T &, CustomContext& ctx) {
|
||||
const char *format(const T &, custom_context& ctx) {
|
||||
ctx.called = true;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
bool called;
|
||||
|
||||
fmt::parse_context parse_context() { return fmt::parse_context(""); }
|
||||
void advance_to(const char *) {}
|
||||
};
|
||||
|
||||
TEST(UtilTest, MakeValueWithCustomFormatter) {
|
||||
::Test t;
|
||||
fmt::internal::value<CustomContext> arg(t);
|
||||
CustomContext ctx = {false};
|
||||
fmt::internal::value<custom_context> arg(t);
|
||||
custom_context ctx = {false};
|
||||
arg.custom.format(&t, ctx);
|
||||
EXPECT_TRUE(ctx.called);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user