From 241414028d97c74fc627d9b77a4b373b901d624e Mon Sep 17 00:00:00 2001 From: Greg Sjaardema Date: Fri, 3 May 2019 08:03:14 -0600 Subject: [PATCH 1/3] Eliminate shadowed variable warnings from gcc-7.2 The gcc-7.2.0 compiler (and others) were giving shadowed variable warnings for this include file. A simple renaming of a couple local variables eliminates the warnings. --- include/fmt/ostream.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/fmt/ostream.h b/include/fmt/ostream.h index 659cbaf37693..4d7fd4b14da5 100644 --- a/include/fmt/ostream.h +++ b/include/fmt/ostream.h @@ -22,7 +22,7 @@ template class formatbuf : public std::basic_streambuf { buffer& buffer_; public: - formatbuf(buffer& buffer) : buffer_(buffer) {} + formatbuf(buffer& buf) : buffer_(buf) {} protected: // The put-area is actually always empty. This makes the implementation @@ -72,26 +72,26 @@ template class is_streamable { // Write the content of buf to os. template void write(std::basic_ostream& os, buffer& buf) { - const Char* data = buf.data(); + const Char* buf_data = buf.data(); typedef std::make_unsigned::type UnsignedStreamSize; UnsignedStreamSize size = buf.size(); UnsignedStreamSize max_size = internal::to_unsigned((std::numeric_limits::max)()); do { UnsignedStreamSize n = size <= max_size ? size : max_size; - os.write(data, static_cast(n)); - data += n; + os.write(buf_data, static_cast(n)); + buf_data += n; size -= n; } while (size != 0); } template -void format_value(buffer& buffer, const T& value) { - internal::formatbuf format_buf(buffer); +void format_value(buffer& buf, const T& value) { + internal::formatbuf format_buf(buf); std::basic_ostream output(&format_buf); output.exceptions(std::ios_base::failbit | std::ios_base::badbit); output << value; - buffer.resize(buffer.size()); + buf.resize(buf.size()); } // Formats an object of type T that has an overloaded ostream operator<<. From 38a85502ed824d34a751ab4a122005a9d4454fd3 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 4 May 2019 09:22:09 -0700 Subject: [PATCH 2/3] Use the same rep type for seconds to prevent overflow --- include/fmt/chrono.h | 26 +++++++++++++++++++------- test/chrono-test.cc | 4 ++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 2b289a879189..9de56df9a15d 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -376,13 +376,24 @@ struct chrono_format_checker { FMT_NORETURN void on_tz_name() { report_no_date(); } }; -template inline int to_int(Int value) { +template inline int to_int(T value) { FMT_ASSERT(value >= (std::numeric_limits::min)() && value <= (std::numeric_limits::max)(), "invalid value"); return static_cast(value); } +template ::value, int>::type = 0> +inline T mod(T x, int y) { + return x % y; +} +template ::value, + int>::type = 0> +inline T mod(T x, int y) { + return std::fmod(x, y); +} + template OutputIt static format_chrono_duration_value(OutputIt out, Rep val, int precision) { @@ -410,8 +421,9 @@ struct chrono_formatter { OutputIt out; int precision; Rep val; + typedef std::chrono::duration seconds; + seconds s; typedef std::chrono::duration milliseconds; - std::chrono::seconds s; milliseconds ms; typedef typename FormatContext::char_type char_type; @@ -421,18 +433,18 @@ struct chrono_formatter { : context(ctx), out(o), val(d.count()), - s(std::chrono::duration_cast(d)), + s(std::chrono::duration_cast(d)), ms(std::chrono::duration_cast(d - s)) {} - int hour() const { return to_int((s.count() / 3600) % 24); } + int hour() const { return to_int(mod((s.count() / 3600), 24)); } int hour12() const { - auto hour = to_int((s.count() / 3600) % 12); + auto hour = to_int(mod((s.count() / 3600), 12)); return hour > 0 ? hour : 12; } - int minute() const { return to_int((s.count() / 60) % 60); } - int second() const { return to_int(s.count() % 60); } + int minute() const { return to_int(mod((s.count() / 60), 60)); } + int second() const { return to_int(mod(s.count(), 60)); } std::tm time() const { auto time = std::tm(); diff --git a/test/chrono-test.cc b/test/chrono-test.cc index a4f563cd1614..8965af92f78e 100644 --- a/test/chrono-test.cc +++ b/test/chrono-test.cc @@ -306,4 +306,8 @@ TEST(ChronoTest, InvalidColons) { fmt::format_error); } +TEST(ChronoTest, LargeDuration) { + EXPECT_EQ("40", fmt::format("{:%S}", std::chrono::duration(1e20))); +} + #endif // FMT_STATIC_THOUSANDS_SEPARATOR From c1d430e61ab306e0e1d454fea6e07b4f66667a65 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 4 May 2019 16:33:17 -0700 Subject: [PATCH 3/3] Improve handling of negative durations --- include/fmt/chrono.h | 13 ++++++++----- test/chrono-test.cc | 4 ++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 9de56df9a15d..39369addd7ce 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -430,11 +430,14 @@ struct chrono_formatter { explicit chrono_formatter(FormatContext& ctx, OutputIt o, std::chrono::duration d) - : context(ctx), - out(o), - val(d.count()), - s(std::chrono::duration_cast(d)), - ms(std::chrono::duration_cast(d - s)) {} + : context(ctx), out(o), val(d.count()) { + if (d.count() < 0) { + d = -d; + *out++ = '-'; + } + s = std::chrono::duration_cast(d); + ms = std::chrono::duration_cast(d - s); + } int hour() const { return to_int(mod((s.count() / 3600), 24)); } diff --git a/test/chrono-test.cc b/test/chrono-test.cc index 8965af92f78e..573606d8dbdf 100644 --- a/test/chrono-test.cc +++ b/test/chrono-test.cc @@ -310,4 +310,8 @@ TEST(ChronoTest, LargeDuration) { EXPECT_EQ("40", fmt::format("{:%S}", std::chrono::duration(1e20))); } +TEST(ChronoTest, NegativeDuration) { + EXPECT_EQ("-00:01", fmt::format("{:%M:%S}", std::chrono::duration(-1))); +} + #endif // FMT_STATIC_THOUSANDS_SEPARATOR