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
This commit is contained in:
Howard Hinnant 2018-04-18 21:47:15 -04:00
parent d53db7a1cb
commit 973bd393bc
3 changed files with 68 additions and 40 deletions

View File

@ -942,33 +942,61 @@ struct is_clock<T, std::void_t<decltype(T::now()), typename T::rep, typename T::
namespace detail { namespace detail {
template<class CharT, class Traits = std::char_traits<CharT>> template<class CharT, class Traits = std::char_traits<CharT>>
class save_stream class save_istream
{ {
std::basic_ios<CharT, Traits>& os_; protected:
std::basic_ios<CharT, Traits>& is_;
CharT fill_; CharT fill_;
std::ios::fmtflags flags_; std::ios::fmtflags flags_;
std::streamsize width_; std::streamsize width_;
std::basic_ostream<CharT, Traits>* tie_;
std::locale loc_; std::locale loc_;
public: public:
~save_stream() ~save_istream()
{ {
os_.fill(fill_); is_.fill(fill_);
os_.flags(flags_); is_.flags(flags_);
os_.width(width_); is_.width(width_);
os_.imbue(loc_); is_.imbue(loc_);
is_.tie(tie_);
} }
save_stream(const save_stream&) = delete; save_istream(const save_istream&) = delete;
save_stream& operator=(const save_stream&) = delete; save_istream& operator=(const save_istream&) = delete;
explicit save_stream(std::basic_ios<CharT, Traits>& os) explicit save_istream(std::basic_ios<CharT, Traits>& is)
: os_(os) : is_(is)
, fill_(os.fill()) , fill_(is.fill())
, flags_(os.flags()) , flags_(is.flags())
, width_(os.width(0)) , width_(is.width(0))
, loc_(os.getloc()) , tie_(is.tie(nullptr))
{} , loc_(is.getloc())
{
if (tie_ != nullptr)
tie_->flush();
}
};
template<class CharT, class Traits = std::char_traits<CharT>>
class save_ostream
: private save_istream<CharT, Traits>
{
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<CharT, Traits>& os)
: save_istream<CharT, Traits>(os)
{
}
}; };
template <class T> template <class T>
@ -1357,7 +1385,7 @@ inline
std::basic_ostream<CharT, Traits>& std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const day& d) operator<<(std::basic_ostream<CharT, Traits>& os, const day& d)
{ {
detail::save_stream<CharT, Traits> _(os); detail::save_ostream<CharT, Traits> _(os);
os.fill('0'); os.fill('0');
os.flags(std::ios::dec | std::ios::right); os.flags(std::ios::dec | std::ios::right);
os.width(2); os.width(2);
@ -1625,7 +1653,7 @@ inline
std::basic_ostream<CharT, Traits>& std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const year& y) operator<<(std::basic_ostream<CharT, Traits>& os, const year& y)
{ {
detail::save_stream<CharT, Traits> _(os); detail::save_ostream<CharT, Traits> _(os);
os.fill('0'); os.fill('0');
os.flags(std::ios::dec | std::ios::internal); os.flags(std::ios::dec | std::ios::internal);
os.width(4 + (y < year{0})); os.width(4 + (y < year{0}));
@ -2731,7 +2759,7 @@ inline
std::basic_ostream<CharT, Traits>& std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_day& ymd) operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_day& ymd)
{ {
detail::save_stream<CharT, Traits> _(os); detail::save_ostream<CharT, Traits> _(os);
os.fill('0'); os.fill('0');
os.flags(std::ios::dec | std::ios::right); os.flags(std::ios::dec | std::ios::right);
os << ymd.year() << '-'; os << ymd.year() << '-';
@ -3644,7 +3672,7 @@ public:
std::basic_ostream<CharT, Traits>& std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const decimal_format_seconds& x) operator<<(std::basic_ostream<CharT, Traits>& os, const decimal_format_seconds& x)
{ {
date::detail::save_stream<CharT, Traits> _(os); date::detail::save_ostream<CharT, Traits> _(os);
os.fill('0'); os.fill('0');
os.flags(std::ios::dec | std::ios::right); os.flags(std::ios::dec | std::ios::right);
os.width(2); os.width(2);
@ -3689,7 +3717,7 @@ public:
std::basic_ostream<CharT, Traits>& std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const decimal_format_seconds& x) operator<<(std::basic_ostream<CharT, Traits>& os, const decimal_format_seconds& x)
{ {
date::detail::save_stream<CharT, Traits> _(os); date::detail::save_ostream<CharT, Traits> _(os);
os.fill('0'); os.fill('0');
os.flags(std::ios::dec | std::ios::right); os.flags(std::ios::dec | std::ios::right);
os.width(2); os.width(2);
@ -3889,7 +3917,7 @@ public:
operator<<(std::basic_ostream<CharT, Traits>& os, const time_of_day_storage& t) operator<<(std::basic_ostream<CharT, Traits>& os, const time_of_day_storage& t)
{ {
using namespace std; using namespace std;
detail::save_stream<CharT, Traits> _(os); detail::save_ostream<CharT, Traits> _(os);
if (t.neg_) if (t.neg_)
os << '-'; os << '-';
os.fill('0'); os.fill('0');
@ -3972,7 +4000,7 @@ public:
operator<<(std::basic_ostream<CharT, Traits>& os, const time_of_day_storage& t) operator<<(std::basic_ostream<CharT, Traits>& os, const time_of_day_storage& t)
{ {
using namespace std; using namespace std;
detail::save_stream<CharT, Traits> _(os); detail::save_ostream<CharT, Traits> _(os);
if (t.neg_) if (t.neg_)
os << '-'; os << '-';
os.fill('0'); os.fill('0');
@ -4062,7 +4090,7 @@ public:
operator<<(std::basic_ostream<CharT, Traits>& os, const time_of_day_storage& t) operator<<(std::basic_ostream<CharT, Traits>& os, const time_of_day_storage& t)
{ {
using namespace std; using namespace std;
detail::save_stream<CharT, Traits> _(os); detail::save_ostream<CharT, Traits> _(os);
if (t.neg_) if (t.neg_)
os << '-'; os << '-';
os.fill('0'); os.fill('0');
@ -4172,7 +4200,7 @@ public:
operator<<(std::basic_ostream<CharT, Traits>& os, const time_of_day_storage& t) operator<<(std::basic_ostream<CharT, Traits>& os, const time_of_day_storage& t)
{ {
using namespace std; using namespace std;
detail::save_stream<CharT, Traits> _(os); detail::save_ostream<CharT, Traits> _(os);
if (t.neg_) if (t.neg_)
os << '-'; os << '-';
os.fill('0'); os.fill('0');
@ -4586,7 +4614,7 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
using namespace std; using namespace std;
using namespace std::chrono; using namespace std::chrono;
using namespace detail; using namespace detail;
date::detail::save_stream<CharT, Traits> ss(os); date::detail::save_ostream<CharT, Traits> ss(os);
os.fill(' '); os.fill(' ');
os.flags(std::ios::skipws | std::ios::dec); os.flags(std::ios::skipws | std::ios::dec);
os.width(0); os.width(0);
@ -4704,7 +4732,7 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
else // *fmt == 'x' else // *fmt == 'x'
{ {
auto const& ymd = fds.ymd; auto const& ymd = fds.ymd;
save_stream<CharT, Traits> _(os); save_ostream<CharT, Traits> _(os);
os.fill('0'); os.fill('0');
os.flags(std::ios::dec | std::ios::right); os.flags(std::ios::dec | std::ios::right);
os.width(2); os.width(2);
@ -4736,7 +4764,7 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
if (modified == CharT{}) if (modified == CharT{})
#endif #endif
{ {
save_stream<CharT, Traits> _(os); save_ostream<CharT, Traits> _(os);
os.fill('0'); os.fill('0');
os.flags(std::ios::dec | std::ios::right); os.flags(std::ios::dec | std::ios::right);
if (y >= 0) if (y >= 0)
@ -4781,7 +4809,7 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
if (modified == CharT{}) if (modified == CharT{})
#endif #endif
{ {
save_stream<CharT, Traits> _(os); save_ostream<CharT, Traits> _(os);
if (*fmt == CharT{'d'}) if (*fmt == CharT{'d'})
os.fill('0'); os.fill('0');
else else
@ -4813,7 +4841,7 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
if (!fds.ymd.ok()) if (!fds.ymd.ok())
os.setstate(std::ios::failbit); os.setstate(std::ios::failbit);
auto const& ymd = fds.ymd; auto const& ymd = fds.ymd;
save_stream<CharT, Traits> _(os); save_ostream<CharT, Traits> _(os);
os.fill('0'); os.fill('0');
os.flags(std::ios::dec | std::ios::right); os.flags(std::ios::dec | std::ios::right);
os.width(2); os.width(2);
@ -4841,7 +4869,7 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
if (!fds.ymd.ok()) if (!fds.ymd.ok())
os.setstate(std::ios::failbit); os.setstate(std::ios::failbit);
auto const& ymd = fds.ymd; auto const& ymd = fds.ymd;
save_stream<CharT, Traits> _(os); save_ostream<CharT, Traits> _(os);
os.fill('0'); os.fill('0');
os.flags(std::ios::dec | std::ios::right); os.flags(std::ios::dec | std::ios::right);
os.width(4); os.width(4);
@ -4878,7 +4906,7 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
os << y; os << y;
else else
{ {
save_stream<CharT, Traits> _(os); save_ostream<CharT, Traits> _(os);
os.fill('0'); os.fill('0');
os.flags(std::ios::dec | std::ios::right); os.flags(std::ios::dec | std::ios::right);
os.width(2); os.width(2);
@ -4941,7 +4969,7 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
auto ld = local_days(fds.ymd); auto ld = local_days(fds.ymd);
auto y = fds.ymd.year(); auto y = fds.ymd.year();
auto doy = ld - local_days(y/jan/1) + days{1}; auto doy = ld - local_days(y/jan/1) + days{1};
save_stream<CharT, Traits> _(os); save_ostream<CharT, Traits> _(os);
os.fill('0'); os.fill('0');
os.flags(std::ios::dec | std::ios::right); os.flags(std::ios::dec | std::ios::right);
os.width(3); os.width(3);
@ -5081,7 +5109,7 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
#else #else
time_of_day<seconds> tod(duration_cast<seconds>(fds.tod.to_duration())); time_of_day<seconds> tod(duration_cast<seconds>(fds.tod.to_duration()));
tod.make12(); tod.make12();
save_stream<CharT, Traits> _(os); save_ostream<CharT, Traits> _(os);
os.fill('0'); os.fill('0');
os.width(2); os.width(2);
os << tod.hours().count() << CharT{':'}; os << tod.hours().count() << CharT{':'};
@ -6019,7 +6047,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
typename basic_istream<CharT, Traits>::sentry ok{is, true}; typename basic_istream<CharT, Traits>::sentry ok{is, true};
if (ok) if (ok)
{ {
date::detail::save_stream<CharT, Traits> ss(is); date::detail::save_istream<CharT, Traits> ss(is);
is.fill(' '); is.fill(' ');
is.flags(std::ios::skipws | std::ios::dec); is.flags(std::ios::skipws | std::ios::dec);
is.width(0); is.width(0);

View File

@ -713,7 +713,7 @@ inline
std::basic_ostream<CharT, Traits>& std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const year& y) operator<<(std::basic_ostream<CharT, Traits>& os, const year& y)
{ {
date::detail::save_stream<CharT, Traits> _(os); date::detail::save_ostream<CharT, Traits> _(os);
os.fill('0'); os.fill('0');
os.flags(std::ios::dec | std::ios::internal); os.flags(std::ios::dec | std::ios::internal);
os.width(4 + (y < year{0})); os.width(4 + (y < year{0}));
@ -875,7 +875,7 @@ inline
std::basic_ostream<CharT, Traits>& std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const weeknum& wn) operator<<(std::basic_ostream<CharT, Traits>& os, const weeknum& wn)
{ {
date::detail::save_stream<CharT, Traits> _(os); date::detail::save_ostream<CharT, Traits> _(os);
os << 'W'; os << 'W';
os.fill('0'); os.fill('0');
os.flags(std::ios::dec | std::ios::right); os.flags(std::ios::dec | std::ios::right);

View File

@ -1224,7 +1224,7 @@ detail::operator<<(std::ostream& os, const Rule& r)
{ {
using namespace date; using namespace date;
using namespace std::chrono; using namespace std::chrono;
detail::save_stream<char> _(os); detail::save_ostream<char> _(os);
os.fill(' '); os.fill(' ');
os.flags(std::ios::dec | std::ios::left); os.flags(std::ios::dec | std::ios::left);
os.width(15); os.width(15);
@ -2541,7 +2541,7 @@ operator<<(std::ostream& os, const time_zone& z)
{ {
using namespace date; using namespace date;
using namespace std::chrono; using namespace std::chrono;
detail::save_stream<char> _(os); detail::save_ostream<char> _(os);
os.fill(' '); os.fill(' ');
os.flags(std::ios::dec | std::ios::left); os.flags(std::ios::dec | std::ios::left);
std::call_once(*z.adjusted_, std::call_once(*z.adjusted_,
@ -2715,7 +2715,7 @@ std::ostream&
operator<<(std::ostream& os, const link& x) operator<<(std::ostream& os, const link& x)
{ {
using namespace date; using namespace date;
detail::save_stream<char> _(os); detail::save_ostream<char> _(os);
os.fill(' '); os.fill(' ');
os.flags(std::ios::dec | std::ios::left); os.flags(std::ios::dec | std::ios::left);
os.width(35); os.width(35);