to_stream sets failbit if unable to format

*  If a formatting flag requests data that is not available in
   the Streamable object, or if the Streamable object answers !ok(),
   failbit is set.
This commit is contained in:
Howard Hinnant 2018-04-06 11:19:44 -04:00
parent 0125d330ab
commit 1d9e49ea21
2 changed files with 317 additions and 280 deletions

View File

@ -4316,28 +4316,33 @@ operator<<(std::basic_ostream<CharT, Traits>& os, const local_time<Duration>& ut
// to_stream // to_stream
constexpr year nanyear{-32768};
template <class Duration> template <class Duration>
struct fields struct fields
{ {
year_month_day ymd{year{0}/0/0}; year_month_day ymd{nanyear/0/0};
weekday wd{7u}; weekday wd{7u};
time_of_day<Duration> tod{}; time_of_day<Duration> tod{};
bool has_tod = false;
fields() = default; fields() = default;
fields(year_month_day ymd_) : ymd(ymd_) {} fields(year_month_day ymd_) : ymd(ymd_) {}
fields(weekday wd_) : wd(wd_) {} fields(weekday wd_) : wd(wd_) {}
fields(time_of_day<Duration> tod_) : tod(tod_) {} fields(time_of_day<Duration> tod_) : tod(tod_), has_tod(true) {}
fields(year_month_day ymd_, weekday wd_) : ymd(ymd_), wd(wd_) {} fields(year_month_day ymd_, weekday wd_) : ymd(ymd_), wd(wd_) {}
fields(year_month_day ymd_, time_of_day<Duration> tod_) : ymd(ymd_), tod(tod_) {} fields(year_month_day ymd_, time_of_day<Duration> tod_) : ymd(ymd_), tod(tod_),
has_tod(true) {}
fields(weekday wd_, time_of_day<Duration> tod_) : wd(wd_), tod(tod_) {} fields(weekday wd_, time_of_day<Duration> tod_) : wd(wd_), tod(tod_), has_tod(true) {}
fields(year_month_day ymd_, weekday wd_, time_of_day<Duration> tod_) fields(year_month_day ymd_, weekday wd_, time_of_day<Duration> tod_)
: ymd(ymd_) : ymd(ymd_)
, wd(wd_) , wd(wd_)
, tod(tod_) , tod(tod_)
, has_tod(true)
{} {}
}; };
@ -4654,7 +4659,12 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
os << CharT{'%'} << modified << *fmt; os << CharT{'%'} << modified << *fmt;
else else
{ {
if (!fds.ymd.ok())
os.setstate(std::ios::failbit);
if (*fmt == 'c' && !fds.has_tod)
os.setstate(std::ios::failbit);
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (*fmt == 'c')
tm = std::tm{}; tm = std::tm{};
auto const& ymd = fds.ymd; auto const& ymd = fds.ymd;
auto ld = local_days(ymd); auto ld = local_days(ymd);
@ -4713,11 +4723,15 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
case 'C': case 'C':
if (command) if (command)
{ {
if (modified == CharT{'O'})
os << CharT{'%'} << modified << *fmt;
else
{
if (!fds.ymd.year().ok())
os.setstate(std::ios::failbit);
auto y = static_cast<int>(fds.ymd.year()); auto y = static_cast<int>(fds.ymd.year());
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
#else
if (modified != CharT{'O'})
#endif #endif
{ {
save_stream<CharT, Traits> _(os); save_stream<CharT, Traits> _(os);
@ -4743,9 +4757,6 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif #endif
else
{
os << CharT{'%'} << modified << *fmt;
} }
command = nullptr; command = nullptr;
modified = CharT{}; modified = CharT{};
@ -4757,11 +4768,15 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
case 'e': case 'e':
if (command) if (command)
{ {
if (modified == CharT{'E'})
os << CharT{'%'} << modified << *fmt;
else
{
if (!fds.ymd.day().ok())
os.setstate(std::ios::failbit);
auto d = static_cast<int>(static_cast<unsigned>(fds.ymd.day())); auto d = static_cast<int>(static_cast<unsigned>(fds.ymd.day()));
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
#else
if (modified != CharT{'E'})
#endif #endif
{ {
save_stream<CharT, Traits> _(os); save_stream<CharT, Traits> _(os);
@ -4781,9 +4796,6 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif #endif
else
{
os << CharT{'%'} << modified << *fmt;
} }
command = nullptr; command = nullptr;
modified = CharT{}; modified = CharT{};
@ -4796,6 +4808,8 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
{ {
if (modified == CharT{}) if (modified == CharT{})
{ {
if (!fds.ymd.ok())
os.setstate(std::ios::failbit);
auto const& ymd = fds.ymd; auto const& ymd = fds.ymd;
save_stream<CharT, Traits> _(os); save_stream<CharT, Traits> _(os);
os.fill('0'); os.fill('0');
@ -4822,6 +4836,8 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
{ {
if (modified == CharT{}) if (modified == CharT{})
{ {
if (!fds.ymd.ok())
os.setstate(std::ios::failbit);
auto const& ymd = fds.ymd; auto const& ymd = fds.ymd;
save_stream<CharT, Traits> _(os); save_stream<CharT, Traits> _(os);
os.fill('0'); os.fill('0');
@ -4849,6 +4865,8 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
{ {
if (modified == CharT{}) if (modified == CharT{})
{ {
if (!fds.ymd.ok())
os.setstate(std::ios::failbit);
auto ld = local_days(fds.ymd); auto ld = local_days(fds.ymd);
auto y = year_month_day{ld + days{3}}.year(); auto y = year_month_day{ld + days{3}}.year();
auto start = local_days((y - years{1})/date::dec/thu[last]) + (mon-thu); auto start = local_days((y - years{1})/date::dec/thu[last]) + (mon-thu);
@ -4879,11 +4897,15 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
case 'I': case 'I':
if (command) if (command)
{ {
if (modified == CharT{'E'})
os << CharT{'%'} << modified << *fmt;
else
{
if (!fds.has_tod)
os.setstate(std::ios::failbit);
auto hms = fds.tod; auto hms = fds.tod;
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
#else
if (modified != CharT{'E'})
#endif #endif
{ {
if (*fmt == CharT{'I'}) if (*fmt == CharT{'I'})
@ -4900,9 +4922,6 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif #endif
else
{
os << CharT{'%'} << modified << *fmt;
} }
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
@ -4915,6 +4934,8 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
{ {
if (modified == CharT{}) if (modified == CharT{})
{ {
if (!fds.ymd.ok())
os.setstate(std::ios::failbit);
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};
@ -4937,11 +4958,15 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
case 'm': case 'm':
if (command) if (command)
{ {
if (modified == CharT{'E'})
os << CharT{'%'} << modified << *fmt;
else
{
if (!fds.ymd.month().ok())
os.setstate(std::ios::failbit);
auto m = static_cast<unsigned>(fds.ymd.month()); auto m = static_cast<unsigned>(fds.ymd.month());
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
#else
if (modified != CharT{'E'})
#endif #endif
{ {
if (m < 10) if (m < 10)
@ -4956,9 +4981,6 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif #endif
else
{
os << CharT{'%'} << modified << *fmt;
} }
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
@ -4969,10 +4991,14 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
case 'M': case 'M':
if (command) if (command)
{ {
if (modified == CharT{'E'})
os << CharT{'%'} << modified << *fmt;
else
{
if (!fds.has_tod)
os.setstate(std::ios::failbit);
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
#else
if (modified != CharT{'E'})
#endif #endif
{ {
if (fds.tod.minutes() < minutes{10}) if (fds.tod.minutes() < minutes{10})
@ -4987,9 +5013,6 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif #endif
else
{
os << CharT{'%'} << modified << *fmt;
} }
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
@ -5017,6 +5040,8 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
{ {
if (modified == CharT{}) if (modified == CharT{})
{ {
if (!fds.has_tod)
os.setstate(std::ios::failbit);
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
const CharT f[] = {'%', *fmt}; const CharT f[] = {'%', *fmt};
tm.tm_hour = static_cast<int>(fds.tod.hours().count()); tm.tm_hour = static_cast<int>(fds.tod.hours().count());
@ -5043,6 +5068,8 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
{ {
if (modified == CharT{}) if (modified == CharT{})
{ {
if (!fds.has_tod)
os.setstate(std::ios::failbit);
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
const CharT f[] = {'%', *fmt}; const CharT f[] = {'%', *fmt};
tm.tm_hour = static_cast<int>(fds.tod.hours().count()); tm.tm_hour = static_cast<int>(fds.tod.hours().count());
@ -5082,6 +5109,8 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
{ {
if (modified == CharT{}) if (modified == CharT{})
{ {
if (!fds.has_tod)
os.setstate(std::ios::failbit);
if (fds.tod.hours() < hours{10}) if (fds.tod.hours() < hours{10})
os << CharT{'0'}; os << CharT{'0'};
os << fds.tod.hours().count() << CharT{':'}; os << fds.tod.hours().count() << CharT{':'};
@ -5102,10 +5131,14 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
case 'S': case 'S':
if (command) if (command)
{ {
if (modified == CharT{'E'})
os << CharT{'%'} << modified << *fmt;
else
{
if (!fds.has_tod)
os.setstate(std::ios::failbit);
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
#else
if (modified != CharT{'E'})
#endif #endif
{ {
os << fds.tod.s_; os << fds.tod.s_;
@ -5118,9 +5151,6 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif #endif
else
{
os << CharT{'%'} << modified << *fmt;
} }
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
@ -5148,6 +5178,8 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
{ {
if (modified == CharT{}) if (modified == CharT{})
{ {
if (!fds.has_tod)
os.setstate(std::ios::failbit);
os << fds.tod; os << fds.tod;
} }
else else
@ -5162,14 +5194,14 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
break; break;
case 'u': case 'u':
if (command) if (command)
{
if (modified == CharT{'E'})
os << CharT{'%'} << modified << *fmt;
else
{ {
auto wd = extract_weekday(os, fds); auto wd = extract_weekday(os, fds);
if (os.fail())
return os;
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
#else
if (modified != CharT{'E'})
#endif #endif
{ {
os << (wd != 0 ? wd : 7u); os << (wd != 0 ? wd : 7u);
@ -5182,9 +5214,6 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif #endif
else
{
os << CharT{'%'} << modified << *fmt;
} }
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
@ -5194,13 +5223,17 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
break; break;
case 'U': case 'U':
if (command) if (command)
{
if (modified == CharT{'E'})
os << CharT{'%'} << modified << *fmt;
else
{ {
auto const& ymd = fds.ymd; auto const& ymd = fds.ymd;
if (!ymd.ok())
os.setstate(std::ios::failbit);
auto ld = local_days(ymd); auto ld = local_days(ymd);
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
#else
if (modified != CharT{'E'})
#endif #endif
{ {
auto st = local_days(sun[1]/jan/ymd.year()); auto st = local_days(sun[1]/jan/ymd.year());
@ -5226,9 +5259,6 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif #endif
else
{
os << CharT{'%'} << modified << *fmt;
} }
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
@ -5239,11 +5269,15 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
case 'V': case 'V':
if (command) if (command)
{ {
if (modified == CharT{'E'})
os << CharT{'%'} << modified << *fmt;
else
{
if (!fds.ymd.ok())
os.setstate(std::ios::failbit);
auto ld = local_days(fds.ymd); auto ld = local_days(fds.ymd);
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
#else
if (modified != CharT{'E'})
#endif #endif
{ {
auto y = year_month_day{ld + days{3}}.year(); auto y = year_month_day{ld + days{3}}.year();
@ -5271,9 +5305,6 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif #endif
else
{
os << CharT{'%'} << modified << *fmt;
} }
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
@ -5315,13 +5346,17 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
break; break;
case 'W': case 'W':
if (command) if (command)
{
if (modified == CharT{'E'})
os << CharT{'%'} << modified << *fmt;
else
{ {
auto const& ymd = fds.ymd; auto const& ymd = fds.ymd;
if (!ymd.ok())
os.setstate(std::ios::failbit);
auto ld = local_days(ymd); auto ld = local_days(ymd);
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
#else
if (modified != CharT{'E'})
#endif #endif
{ {
auto st = local_days(mon[1]/jan/ymd.year()); auto st = local_days(mon[1]/jan/ymd.year());
@ -5347,9 +5382,6 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif #endif
else
{
os << CharT{'%'} << modified << *fmt;
} }
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
@ -5364,6 +5396,8 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
os << CharT{'%'} << modified << *fmt; os << CharT{'%'} << modified << *fmt;
else else
{ {
if (!fds.has_tod)
os.setstate(std::ios::failbit);
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
tm = std::tm{}; tm = std::tm{};
tm.tm_sec = static_cast<int>(fds.tod.seconds().count()); tm.tm_sec = static_cast<int>(fds.tod.seconds().count());
@ -5388,6 +5422,8 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
case 'y': case 'y':
if (command) if (command)
{ {
if (!fds.ymd.year().ok())
os.setstate(std::ios::failbit);
auto y = static_cast<int>(fds.ymd.year()); auto y = static_cast<int>(fds.ymd.year());
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
@ -5415,11 +5451,15 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
case 'Y': case 'Y':
if (command) if (command)
{ {
if (modified == CharT{'O'})
os << CharT{'%'} << modified << *fmt;
else
{
if (!fds.ymd.year().ok())
os.setstate(std::ios::failbit);
auto y = fds.ymd.year(); auto y = fds.ymd.year();
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
if (modified == CharT{}) if (modified == CharT{})
#else
if (modified != CharT{'O'})
#endif #endif
{ {
os << y; os << y;
@ -5432,9 +5472,6 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
} }
#endif #endif
else
{
os << CharT{'%'} << modified << *fmt;
} }
modified = CharT{}; modified = CharT{};
command = nullptr; command = nullptr;
@ -5572,7 +5609,7 @@ std::basic_ostream<CharT, Traits>&
to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const month& m) to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const month& m)
{ {
using CT = std::chrono::seconds; using CT = std::chrono::seconds;
fields<CT> fds{m/0/0}; fields<CT> fds{m/0/nanyear};
return to_stream(os, fmt, fds); return to_stream(os, fmt, fds);
} }
@ -5582,7 +5619,7 @@ std::basic_ostream<CharT, Traits>&
to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const day& d) to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const day& d)
{ {
using CT = std::chrono::seconds; using CT = std::chrono::seconds;
fields<CT> fds{d/0/0}; fields<CT> fds{d/0/nanyear};
return to_stream(os, fmt, fds); return to_stream(os, fmt, fds);
} }
@ -5612,7 +5649,7 @@ std::basic_ostream<CharT, Traits>&
to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const month_day& md) to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const month_day& md)
{ {
using CT = std::chrono::seconds; using CT = std::chrono::seconds;
fields<CT> fds{md/0}; fields<CT> fds{md/nanyear};
return to_stream(os, fmt, fds); return to_stream(os, fmt, fds);
} }

View File

@ -69,10 +69,10 @@ main()
assert(os.str() == "32767-12-31 00:00:01.2096"); assert(os.str() == "32767-12-31 00:00:01.2096");
os.str(""); os.str("");
os << format("%F %T", jan/1/year::min()); os << format("%F", jan/1/year::min());
assert(os.str() == "-32767-01-01 00:00:00"); assert(os.str() == "-32767-01-01");
os.str(""); os.str("");
os << format("%F %T", dec/last/year::max()); os << format("%F", dec/last/year::max());
assert(os.str() == "32767-12-31 00:00:00"); assert(os.str() == "32767-12-31");
os.str(""); os.str("");
} }