Implement fill/align/width parsing in chrono formatter

This commit is contained in:
Victor Zverovich
2018-12-16 09:08:11 -08:00
parent 1f92f8a9d8
commit 3e01376e08
3 changed files with 137 additions and 83 deletions
+51 -5
View File
@@ -370,12 +370,50 @@ template <> FMT_CONSTEXPR const char *get_units<std::ratio<3600>>() {
template <typename Rep, typename Period, typename Char>
struct formatter<std::chrono::duration<Rep, Period>, Char> {
private:
align_spec spec;
internal::arg_ref<Char> width_ref;
mutable basic_string_view<Char> format_str;
typedef std::chrono::duration<Rep, Period> duration;
struct spec_handler {
formatter &f;
basic_parse_context<Char> &context;
typedef internal::arg_ref<Char> arg_ref_type;
template <typename Id>
FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {
context.check_arg_id(arg_id);
return arg_ref_type(arg_id);
}
FMT_CONSTEXPR arg_ref_type make_arg_ref(internal::auto_id) {
return arg_ref_type(context.next_arg_id());
}
void on_error(const char *msg) { throw format_error(msg); }
void on_fill(Char fill) { f.spec.fill_ = fill; }
void on_align(alignment align) { f.spec.align_ = align; }
void on_width(unsigned width) { f.spec.width_ = width; }
template <typename Id>
void on_dynamic_width(Id arg_id) {
f.width_ref = make_arg_ref(arg_id);
}
};
public:
formatter() : spec() {}
FMT_CONSTEXPR auto parse(basic_parse_context<Char> &ctx)
-> decltype(ctx.begin()) {
auto begin = ctx.begin(), end = ctx.end();
if (begin == end) return begin;
spec_handler handler{*this, ctx};
begin = internal::parse_align(begin, end, handler);
if (begin == end) return begin;
begin = internal::parse_width(begin, end, handler);
end = parse_chrono_format(begin, end, internal::chrono_format_checker());
format_str = basic_string_view<Char>(&*begin, end - begin);
return end;
@@ -386,13 +424,21 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
-> decltype(ctx.out()) {
auto begin = format_str.begin(), end = format_str.end();
if (begin == end || *begin == '}') {
memory_buffer buf;
if (const char *unit = get_units<Period>())
return format_to(ctx.out(), "{}{}", d.count(), unit);
if (Period::den == 1)
return format_to(ctx.out(), "{}[{}]s", d.count(), Period::num);
return format_to(ctx.out(), "{}[{}/{}]s",
d.count(), Period::num, Period::den);
format_to(buf, "{}{}", d.count(), unit);
else if (Period::den == 1)
format_to(buf, "{}[{}]s", d.count(), Period::num);
else
format_to(buf, "{}[{}/{}]s", d.count(), Period::num, Period::den);
typedef output_range<decltype(ctx.out()), Char> range;
basic_writer<range> w(range(ctx.out()));
internal::handle_dynamic_spec<internal::width_checker>(
spec.width_, width_ref, ctx);
w.write(buf.data(), buf.size(), spec);
return w.out();
}
// TODO: use fill and align
internal::chrono_formatter<FormatContext> f(ctx);
f.s = std::chrono::duration_cast<std::chrono::seconds>(d);
f.ms = std::chrono::duration_cast<std::chrono::milliseconds>(d - f.s);