Return iterator from the format method

This commit is contained in:
Victor Zverovich 2018-01-14 11:00:27 -08:00
parent 67928eae28
commit 91ee9c9acd
7 changed files with 66 additions and 38 deletions

View File

@ -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) {}
};
}

View File

@ -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:

View File

@ -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();
}
};

View File

@ -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>

View File

@ -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;

View File

@ -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);
}
};
}

View File

@ -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);
}