Implement fill/align/width for strftime-like formatting

This commit is contained in:
Victor Zverovich 2018-12-19 06:39:58 -08:00
parent 3e01376e08
commit 77a7244804
3 changed files with 25 additions and 15 deletions

View File

@ -217,17 +217,17 @@ inline int to_int(Int value) {
return static_cast<int>(value); return static_cast<int>(value);
} }
template <typename FormatContext> template <typename FormatContext, typename OutputIt>
struct chrono_formatter { struct chrono_formatter {
FormatContext &context; FormatContext &context;
typename FormatContext::iterator out; OutputIt out;
std::chrono::seconds s; std::chrono::seconds s;
std::chrono::milliseconds ms; std::chrono::milliseconds ms;
typedef typename FormatContext::char_type char_type; typedef typename FormatContext::char_type char_type;
explicit chrono_formatter(FormatContext &ctx) explicit chrono_formatter(FormatContext &ctx, OutputIt o)
: context(ctx), out(ctx.out()) {} : context(ctx), out(o) {}
int hour() const { return to_int((s.count() / 3600) % 24); } int hour() const { return to_int((s.count() / 3600) % 24); }
@ -423,27 +423,27 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
auto format(const duration &d, FormatContext &ctx) auto format(const duration &d, FormatContext &ctx)
-> decltype(ctx.out()) { -> decltype(ctx.out()) {
auto begin = format_str.begin(), end = format_str.end(); auto begin = format_str.begin(), end = format_str.end();
memory_buffer buf;
typedef output_range<decltype(ctx.out()), Char> range;
basic_writer<range> w(range(ctx.out()));
if (begin == end || *begin == '}') { if (begin == end || *begin == '}') {
memory_buffer buf;
if (const char *unit = get_units<Period>()) if (const char *unit = get_units<Period>())
format_to(buf, "{}{}", d.count(), unit); format_to(buf, "{}{}", d.count(), unit);
else if (Period::den == 1) else if (Period::den == 1)
format_to(buf, "{}[{}]s", d.count(), Period::num); format_to(buf, "{}[{}]s", d.count(), Period::num);
else else
format_to(buf, "{}[{}/{}]s", d.count(), Period::num, Period::den); 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>( internal::handle_dynamic_spec<internal::width_checker>(
spec.width_, width_ref, ctx); spec.width_, width_ref, ctx);
w.write(buf.data(), buf.size(), spec); } else {
return w.out(); auto out = std::back_inserter(buf);
internal::chrono_formatter<FormatContext, decltype(out)> f(ctx, out);
f.s = std::chrono::duration_cast<std::chrono::seconds>(d);
f.ms = std::chrono::duration_cast<std::chrono::milliseconds>(d - f.s);
parse_chrono_format(begin, end, f);
} }
// TODO: use fill and align w.write(buf.data(), buf.size(), spec);
internal::chrono_formatter<FormatContext> f(ctx); return w.out();
f.s = std::chrono::duration_cast<std::chrono::seconds>(d);
f.ms = std::chrono::duration_cast<std::chrono::milliseconds>(d - f.s);
parse_chrono_format(begin, end, f);
return f.out;
} }
}; };

View File

@ -479,6 +479,9 @@ class basic_memory_buffer: private Allocator, public internal::basic_buffer<T> {
void grow(std::size_t size) FMT_OVERRIDE; void grow(std::size_t size) FMT_OVERRIDE;
public: public:
typedef T value_type;
typedef const T &const_reference;
explicit basic_memory_buffer(const Allocator &alloc = Allocator()) explicit basic_memory_buffer(const Allocator &alloc = Allocator())
: Allocator(alloc) { : Allocator(alloc) {
this->set(store_, SIZE); this->set(store_, SIZE);

View File

@ -97,6 +97,13 @@ TEST(ChronoTest, Align) {
EXPECT_EQ("42s ", fmt::format("{:{}}", s, 5)); EXPECT_EQ("42s ", fmt::format("{:{}}", s, 5));
EXPECT_EQ(" 42s", fmt::format("{:>5}", s)); EXPECT_EQ(" 42s", fmt::format("{:>5}", s));
EXPECT_EQ("**42s**", fmt::format("{:*^7}", s)); EXPECT_EQ("**42s**", fmt::format("{:*^7}", s));
EXPECT_EQ("03:25:45 ",
fmt::format("{:12%H:%M:%S}", std::chrono::seconds(12345)));
EXPECT_EQ(" 03:25:45",
fmt::format("{:>12%H:%M:%S}", std::chrono::seconds(12345)));
EXPECT_EQ("~~03:25:45~~",
fmt::format("{:~^12%H:%M:%S}", std::chrono::seconds(12345)));
} }
TEST(ChronoTest, FormatSpecs) { TEST(ChronoTest, FormatSpecs) {