From 973bd393bc52911405eaed23e425ef595e204324 Mon Sep 17 00:00:00 2001 From: Howard Hinnant Date: Wed, 18 Apr 2018 21:47:15 -0400 Subject: [PATCH] Respect and minimize tie/flush in from/to_stream * Save/restore tie, setting it to nullptr during the operation * On construction tie_->flush() * For ostreams only, flush if unitbuf --- include/date/date.h | 98 ++++++++++++++++++++++++++--------------- include/date/iso_week.h | 4 +- src/tz.cpp | 6 +-- 3 files changed, 68 insertions(+), 40 deletions(-) diff --git a/include/date/date.h b/include/date/date.h index c41ec1f..8bbb93a 100644 --- a/include/date/date.h +++ b/include/date/date.h @@ -942,33 +942,61 @@ struct is_clock> -class save_stream +class save_istream { - std::basic_ios& os_; +protected: + std::basic_ios& is_; CharT fill_; std::ios::fmtflags flags_; std::streamsize width_; + std::basic_ostream* tie_; std::locale loc_; public: - ~save_stream() + ~save_istream() { - os_.fill(fill_); - os_.flags(flags_); - os_.width(width_); - os_.imbue(loc_); + is_.fill(fill_); + is_.flags(flags_); + is_.width(width_); + is_.imbue(loc_); + is_.tie(tie_); } - save_stream(const save_stream&) = delete; - save_stream& operator=(const save_stream&) = delete; + save_istream(const save_istream&) = delete; + save_istream& operator=(const save_istream&) = delete; - explicit save_stream(std::basic_ios& os) - : os_(os) - , fill_(os.fill()) - , flags_(os.flags()) - , width_(os.width(0)) - , loc_(os.getloc()) - {} + explicit save_istream(std::basic_ios& is) + : is_(is) + , fill_(is.fill()) + , flags_(is.flags()) + , width_(is.width(0)) + , tie_(is.tie(nullptr)) + , loc_(is.getloc()) + { + if (tie_ != nullptr) + tie_->flush(); + } +}; + +template> +class save_ostream + : private save_istream +{ +public: + ~save_ostream() + { + if ((this->flags_ & std::ios::unitbuf) && !std::uncaught_exception() && + this->is_.good()) + this->is_.rdbuf()->pubsync(); + } + + save_ostream(const save_ostream&) = delete; + save_ostream& operator=(const save_ostream&) = delete; + + explicit save_ostream(std::basic_ios& os) + : save_istream(os) + { + } }; template @@ -1357,7 +1385,7 @@ inline std::basic_ostream& operator<<(std::basic_ostream& os, const day& d) { - detail::save_stream _(os); + detail::save_ostream _(os); os.fill('0'); os.flags(std::ios::dec | std::ios::right); os.width(2); @@ -1625,7 +1653,7 @@ inline std::basic_ostream& operator<<(std::basic_ostream& os, const year& y) { - detail::save_stream _(os); + detail::save_ostream _(os); os.fill('0'); os.flags(std::ios::dec | std::ios::internal); os.width(4 + (y < year{0})); @@ -2731,7 +2759,7 @@ inline std::basic_ostream& operator<<(std::basic_ostream& os, const year_month_day& ymd) { - detail::save_stream _(os); + detail::save_ostream _(os); os.fill('0'); os.flags(std::ios::dec | std::ios::right); os << ymd.year() << '-'; @@ -3644,7 +3672,7 @@ public: std::basic_ostream& operator<<(std::basic_ostream& os, const decimal_format_seconds& x) { - date::detail::save_stream _(os); + date::detail::save_ostream _(os); os.fill('0'); os.flags(std::ios::dec | std::ios::right); os.width(2); @@ -3689,7 +3717,7 @@ public: std::basic_ostream& operator<<(std::basic_ostream& os, const decimal_format_seconds& x) { - date::detail::save_stream _(os); + date::detail::save_ostream _(os); os.fill('0'); os.flags(std::ios::dec | std::ios::right); os.width(2); @@ -3889,7 +3917,7 @@ public: operator<<(std::basic_ostream& os, const time_of_day_storage& t) { using namespace std; - detail::save_stream _(os); + detail::save_ostream _(os); if (t.neg_) os << '-'; os.fill('0'); @@ -3972,7 +4000,7 @@ public: operator<<(std::basic_ostream& os, const time_of_day_storage& t) { using namespace std; - detail::save_stream _(os); + detail::save_ostream _(os); if (t.neg_) os << '-'; os.fill('0'); @@ -4062,7 +4090,7 @@ public: operator<<(std::basic_ostream& os, const time_of_day_storage& t) { using namespace std; - detail::save_stream _(os); + detail::save_ostream _(os); if (t.neg_) os << '-'; os.fill('0'); @@ -4172,7 +4200,7 @@ public: operator<<(std::basic_ostream& os, const time_of_day_storage& t) { using namespace std; - detail::save_stream _(os); + detail::save_ostream _(os); if (t.neg_) os << '-'; os.fill('0'); @@ -4586,7 +4614,7 @@ to_stream(std::basic_ostream& os, const CharT* fmt, using namespace std; using namespace std::chrono; using namespace detail; - date::detail::save_stream ss(os); + date::detail::save_ostream ss(os); os.fill(' '); os.flags(std::ios::skipws | std::ios::dec); os.width(0); @@ -4704,7 +4732,7 @@ to_stream(std::basic_ostream& os, const CharT* fmt, else // *fmt == 'x' { auto const& ymd = fds.ymd; - save_stream _(os); + save_ostream _(os); os.fill('0'); os.flags(std::ios::dec | std::ios::right); os.width(2); @@ -4736,7 +4764,7 @@ to_stream(std::basic_ostream& os, const CharT* fmt, if (modified == CharT{}) #endif { - save_stream _(os); + save_ostream _(os); os.fill('0'); os.flags(std::ios::dec | std::ios::right); if (y >= 0) @@ -4781,7 +4809,7 @@ to_stream(std::basic_ostream& os, const CharT* fmt, if (modified == CharT{}) #endif { - save_stream _(os); + save_ostream _(os); if (*fmt == CharT{'d'}) os.fill('0'); else @@ -4813,7 +4841,7 @@ to_stream(std::basic_ostream& os, const CharT* fmt, if (!fds.ymd.ok()) os.setstate(std::ios::failbit); auto const& ymd = fds.ymd; - save_stream _(os); + save_ostream _(os); os.fill('0'); os.flags(std::ios::dec | std::ios::right); os.width(2); @@ -4841,7 +4869,7 @@ to_stream(std::basic_ostream& os, const CharT* fmt, if (!fds.ymd.ok()) os.setstate(std::ios::failbit); auto const& ymd = fds.ymd; - save_stream _(os); + save_ostream _(os); os.fill('0'); os.flags(std::ios::dec | std::ios::right); os.width(4); @@ -4878,7 +4906,7 @@ to_stream(std::basic_ostream& os, const CharT* fmt, os << y; else { - save_stream _(os); + save_ostream _(os); os.fill('0'); os.flags(std::ios::dec | std::ios::right); os.width(2); @@ -4941,7 +4969,7 @@ to_stream(std::basic_ostream& os, const CharT* fmt, auto ld = local_days(fds.ymd); auto y = fds.ymd.year(); auto doy = ld - local_days(y/jan/1) + days{1}; - save_stream _(os); + save_ostream _(os); os.fill('0'); os.flags(std::ios::dec | std::ios::right); os.width(3); @@ -5081,7 +5109,7 @@ to_stream(std::basic_ostream& os, const CharT* fmt, #else time_of_day tod(duration_cast(fds.tod.to_duration())); tod.make12(); - save_stream _(os); + save_ostream _(os); os.fill('0'); os.width(2); os << tod.hours().count() << CharT{':'}; @@ -6019,7 +6047,7 @@ from_stream(std::basic_istream& is, const CharT* fmt, typename basic_istream::sentry ok{is, true}; if (ok) { - date::detail::save_stream ss(is); + date::detail::save_istream ss(is); is.fill(' '); is.flags(std::ios::skipws | std::ios::dec); is.width(0); diff --git a/include/date/iso_week.h b/include/date/iso_week.h index 5bbeb0c..fb6df1b 100644 --- a/include/date/iso_week.h +++ b/include/date/iso_week.h @@ -713,7 +713,7 @@ inline std::basic_ostream& operator<<(std::basic_ostream& os, const year& y) { - date::detail::save_stream _(os); + date::detail::save_ostream _(os); os.fill('0'); os.flags(std::ios::dec | std::ios::internal); os.width(4 + (y < year{0})); @@ -875,7 +875,7 @@ inline std::basic_ostream& operator<<(std::basic_ostream& os, const weeknum& wn) { - date::detail::save_stream _(os); + date::detail::save_ostream _(os); os << 'W'; os.fill('0'); os.flags(std::ios::dec | std::ios::right); diff --git a/src/tz.cpp b/src/tz.cpp index f4a819b..64495c3 100644 --- a/src/tz.cpp +++ b/src/tz.cpp @@ -1224,7 +1224,7 @@ detail::operator<<(std::ostream& os, const Rule& r) { using namespace date; using namespace std::chrono; - detail::save_stream _(os); + detail::save_ostream _(os); os.fill(' '); os.flags(std::ios::dec | std::ios::left); os.width(15); @@ -2541,7 +2541,7 @@ operator<<(std::ostream& os, const time_zone& z) { using namespace date; using namespace std::chrono; - detail::save_stream _(os); + detail::save_ostream _(os); os.fill(' '); os.flags(std::ios::dec | std::ios::left); std::call_once(*z.adjusted_, @@ -2715,7 +2715,7 @@ std::ostream& operator<<(std::ostream& os, const link& x) { using namespace date; - detail::save_stream _(os); + detail::save_ostream _(os); os.fill(' '); os.flags(std::ios::dec | std::ios::left); os.width(35);