From 1e7e7a214d58564c0757f36498783635055c829e Mon Sep 17 00:00:00 2001 From: Howard Hinnant Date: Sun, 26 Feb 2017 14:10:10 -0500 Subject: [PATCH] Simplify the implementation of format and parse: * For format, all a type must do is implement to_stream. * For parse, each type X must specialize parse_manip. Each specialization must include a public typedef to itself named type. * Each parse_manip specialization must have a stream extraction operator. * This commit depends on expression-SFINAE. If this commit breaks your build, it is likely that your compiler/version does not support expression-SFINAE. To fix this NO_EXPRESSION_SFINAE needs to be defined in the configuration area of date.h for that compiler/version. --- date.h | 691 ++++++++++--------------- test/date_test/format/range.pass.cpp | 8 + test/date_test/parse.pass.cpp | 8 + tz.h | 748 +++++++++------------------ 4 files changed, 513 insertions(+), 942 deletions(-) diff --git a/date.h b/date.h index a9a54ff..6fa5ca3 100644 --- a/date.h +++ b/date.h @@ -3386,6 +3386,22 @@ operator/(const month_weekday_last& mwdl, int y) NOEXCEPT return year(y) / mwdl; } +template +struct fields; + +template +void +to_stream(std::basic_ostream& os, const CharT* fmt, + const fields& fds, const std::string* abbrev = nullptr, + const std::chrono::seconds* offset_sec = nullptr); + +template +void +parse(std::basic_istream& is, + const CharT* fmt, fields& fds, + std::basic_string* abbrev = nullptr, + std::chrono::minutes* offset = nullptr); + // time_of_day enum {am = 1, pm}; @@ -3531,22 +3547,6 @@ public: } }; -template -struct fields; - -template -void -to_stream(std::basic_ostream& os, const CharT* fmt, - const fields& fds, const std::string* abbrev = nullptr, - const std::chrono::seconds* offset_sec = nullptr); - -template -void -parse(std::basic_istream& is, - const CharT* fmt, fields& fds, - std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr); - enum class classify { not_valid, @@ -3911,15 +3911,15 @@ public: template friend void - detail::to_stream(std::basic_ostream& os, const CharT* fmt, - const detail::fields& fds, const std::string* abbrev, + date::to_stream(std::basic_ostream& os, const CharT* fmt, + const fields& fds, const std::string* abbrev, const std::chrono::seconds* offset_sec); template friend void - detail::parse(std::basic_istream& is, const CharT* fmt, - detail::fields& fds, + date::parse(std::basic_istream& is, const CharT* fmt, + fields& fds, std::basic_string* abbrev, std::chrono::minutes* offset); }; @@ -4015,15 +4015,15 @@ public: template friend void - detail::to_stream(std::basic_ostream& os, const CharT* fmt, - const detail::fields& fds, const std::string* abbrev, + date::to_stream(std::basic_ostream& os, const CharT* fmt, + const fields& fds, const std::string* abbrev, const std::chrono::seconds* offset_sec); template friend void - detail::parse(std::basic_istream& is, const CharT* fmt, - detail::fields& fds, + date::parse(std::basic_istream& is, const CharT* fmt, + fields& fds, std::basic_string* abbrev, std::chrono::minutes* offset); }; @@ -4130,9 +4130,6 @@ operator<<(std::basic_ostream& os, const local_time& ut // to_stream -namespace detail -{ - template struct fields { @@ -4969,7 +4966,16 @@ to_stream(std::basic_ostream& os, const CharT* fmt, os << modified; } -} // namespace detail +template +inline +void +to_stream(std::basic_ostream& os, const CharT* fmt, + const year_month_day& ymd) +{ + using CT = std::chrono::seconds; + fields fds{ymd, time_of_day{}}; + to_stream(os, fmt, fds); +} template inline @@ -4979,8 +4985,8 @@ to_stream(std::basic_ostream& os, const CharT* fmt, { using Duration = std::chrono::duration; using CT = typename std::common_type::type; - detail::fields fds{year_month_day{}, time_of_day{d}}; - detail::to_stream(os, fmt, fds); + fields fds{year_month_day{}, time_of_day{d}}; + to_stream(os, fmt, fds); } template @@ -4991,8 +4997,8 @@ to_stream(std::basic_ostream& os, const CharT* fmt, { using CT = typename std::common_type::type; auto ld = floor(tp); - detail::fields fds{year_month_day{ld}, time_of_day{tp-ld}}; - detail::to_stream(os, fmt, fds, abbrev, offset_sec); + fields fds{year_month_day{ld}, time_of_day{tp-ld}}; + to_stream(os, fmt, fds, abbrev, offset_sec); } template @@ -5004,14 +5010,84 @@ to_stream(std::basic_ostream& os, const CharT* fmt, const std::string abbrev("UTC"); CONSTDATA std::chrono::seconds offset{0}; auto sd = floor(tp); - detail::fields fds{year_month_day{sd}, time_of_day{tp-sd}}; - detail::to_stream(os, fmt, fds, &abbrev, &offset); + fields fds{year_month_day{sd}, time_of_day{tp-sd}}; + to_stream(os, fmt, fds, &abbrev, &offset); } // format +#ifndef NO_EXPRESSION_SFINAE + +template +auto +format(const std::locale& loc, const CharT* fmt, const Streamable& tp) + -> decltype(to_stream(std::declval&>(), fmt, tp), + std::basic_string{}) +{ + std::basic_ostringstream os; + os.imbue(loc); + to_stream(os, fmt, tp); + return os.str(); +} + +template +auto +format(const CharT* fmt, const Streamable& tp) + -> decltype(to_stream(std::declval&>(), fmt, tp), + std::basic_string{}) +{ + std::basic_ostringstream os; + to_stream(os, fmt, tp); + return os.str(); +} + +template +auto +format(const std::locale& loc, const std::basic_string& fmt, + const Streamable& tp) + -> decltype(to_stream(std::declval&>(), fmt, tp), + std::basic_string{}) +{ + std::basic_ostringstream os; + os.imbue(loc); + to_stream(os, fmt.c_str(), tp); + return os.str(); +} + +template +auto +format(const std::basic_string& fmt, const Streamable& tp) + -> decltype(to_stream(std::declval&>(), fmt, tp), + std::basic_string{}) +{ + std::basic_ostringstream os; + to_stream(os, fmt.c_str(), tp); + return os.str(); +} + +#else // NO_EXPRESSION_SFINAE + // const CharT* formats +template +std::basic_string +format(const std::locale& loc, const CharT* fmt, const year_month_day& ymd) +{ + std::basic_ostringstream os; + os.imbue(loc); + to_stream(os, fmt, ymd); + return os.str(); +} + +template +std::basic_string +format(const CharT* fmt, const year_month_day& ymd) +{ + std::basic_ostringstream os; + to_stream(os, fmt, ymd); + return os.str(); +} + template std::basic_string format(const std::locale& loc, const CharT* fmt, const local_time& tp) @@ -5072,6 +5148,26 @@ format(const CharT* fmt, const std::chrono::duration& d) // basic_string formats +template +std::basic_string +format(const std::locale& loc, const std::basic_string& fmt, + const year_month_day& ymd) +{ + std::basic_ostringstream os; + os.imbue(loc); + to_stream(os, fmt.c_str(), ymd); + return os.str(); +} + +template +std::basic_string +format(const std::basic_string& fmt, const year_month_day& ymd) +{ + std::basic_ostringstream os; + to_stream(os, fmt.c_str(), ymd); + return os.str(); +} + template std::basic_string format(const std::locale& loc, const std::basic_string& fmt, @@ -5133,6 +5229,8 @@ format(const std::basic_string& fmt, return os.str(); } +#endif // NO_EXPRESSION_SFINAE + // parse namespace detail @@ -5366,6 +5464,8 @@ read(std::basic_istream& is, rld a0, Args&& ...args) read(is, std::forward(args)...); } +} // namespace detail; + template void parse(std::basic_istream& is, const CharT* fmt, fields& fds, @@ -6255,7 +6355,7 @@ parse(std::basic_istream& is, const CharT* fmt, fields& goto broken; } fds.tod = time_of_day(hours{h} + minutes{min}); - fds.tod.s_ = decimal_format_seconds{s}; + fds.tod.s_ = detail::decimal_format_seconds{s}; if (abbrev != nullptr) *abbrev = std::move(temp_abbrev); if (offset != nullptr) @@ -6267,16 +6367,127 @@ broken: is.setstate(ios_base::failbit); } -template > -struct parse_local_manip +template > +struct parse_manip; + +template +inline +typename parse_manip::type +parse(const std::basic_string& format, Parsable& tp) { + return {format, tp}; +} + +template +inline +typename parse_manip::type +parse(const std::basic_string& format, Parsable& tp, + std::basic_string& abbrev) +{ + return {format, tp, &abbrev}; +} + +template +inline +typename parse_manip::type +parse(const std::basic_string& format, Parsable& tp, + std::chrono::minutes& offset) +{ + return {format, tp, nullptr, &offset}; +} + +template +inline +typename parse_manip::type +parse(const std::basic_string& format, Parsable& tp, + std::basic_string& abbrev, std::chrono::minutes& offset) +{ + return {format, tp, &abbrev, &offset}; +} + +// const CharT* formats + +template +inline +typename parse_manip::type +parse(const CharT* format, Parsable& tp) +{ + return {format, tp}; +} + +template +inline +typename parse_manip::type +parse(const CharT* format, Parsable& tp, std::basic_string& abbrev) +{ + return {format, tp, &abbrev}; +} + +template +inline +typename parse_manip::type +parse(const CharT* format, Parsable& tp, std::chrono::minutes& offset) +{ + return {format, tp, nullptr, &offset}; +} + +template +inline +typename parse_manip::type +parse(const CharT* format, Parsable& tp, + std::basic_string& abbrev, std::chrono::minutes& offset) +{ + return {format, tp, &abbrev, &offset}; +} + +template +struct parse_manip +{ + using type = parse_manip; + const std::basic_string format_; + year_month_day& ymd_; + std::basic_string* abbrev_; + std::chrono::minutes* offset_; + + parse_manip(std::basic_string format, + year_month_day& ymd, std::basic_string* abbrev = nullptr, + std::chrono::minutes* offset = nullptr) + : format_(std::move(format)) + , ymd_(ymd) + , abbrev_(abbrev) + , offset_(offset) + {} +}; + +template +inline +std::basic_istream& +operator>>(std::basic_istream& is, + const parse_manip& x) +{ + using namespace std; + using namespace std::chrono; + using CT = seconds; + fields fds{}; + parse(is, x.format_.c_str(), fds, x.abbrev_, x.offset_); + if (!fds.ymd.ok()) + is.setstate(ios::failbit); + if (!is.fail()) + x.ymd_ = fds.ymd; + return is; +} + +template +struct parse_manip, CharT, Traits> +{ + using type = parse_manip; const std::basic_string format_; local_time& tp_; std::basic_string* abbrev_; std::chrono::minutes* offset_; public: - parse_local_manip(std::basic_string format, + parse_manip(std::basic_string format, local_time& tp, std::basic_string* abbrev = nullptr, std::chrono::minutes* offset = nullptr) : format_(std::move(format)) @@ -6291,7 +6502,7 @@ template inline std::basic_istream& operator>>(std::basic_istream& is, - const parse_local_manip& x) + const parse_manip, CharT, Traits>& x) { using namespace std; using namespace std::chrono; @@ -6305,16 +6516,17 @@ operator>>(std::basic_istream& is, return is; } -template > -struct parse_sys_manip +template +struct parse_manip, CharT, Traits> { + using type = parse_manip; const std::basic_string format_; sys_time& tp_; std::basic_string* abbrev_; std::chrono::minutes* offset_; public: - parse_sys_manip(std::basic_string format, + parse_manip(std::basic_string format, sys_time& tp, std::basic_string* abbrev = nullptr, std::chrono::minutes* offset = nullptr) : format_(std::move(format)) @@ -6328,7 +6540,7 @@ public: template std::basic_istream& operator>>(std::basic_istream& is, - const parse_sys_manip& x) + const parse_manip, CharT, Traits>& x) { using namespace std; using namespace std::chrono; @@ -6345,28 +6557,31 @@ operator>>(std::basic_istream& is, return is; } -template > -struct parse_duration +template +struct parse_manip, CharT, Traits> { + using type = parse_manip; + using Duration = std::chrono::duration; const std::basic_string format_; Duration& d_; public: - parse_duration(std::basic_string format, Duration& d) + parse_manip(std::basic_string format, Duration& d) : format_(std::move(format)) , d_(d) {} }; -template +template inline std::basic_istream& operator>>(std::basic_istream& is, - const parse_duration& x) + const parse_manip, CharT, Traits>& x) { using namespace std; using namespace std::chrono; + using Duration = std::chrono::duration; using CT = typename common_type::type; fields fds{}; parse(is, x.format_.c_str(), fds); @@ -6377,105 +6592,6 @@ operator>>(std::basic_istream& is, return is; } -} // namespace detail - -template -inline -detail::parse_sys_manip -parse(const std::basic_string& format, sys_time& tp) -{ - return {format, tp}; -} - -template -inline -detail::parse_sys_manip -parse(const std::basic_string& format, sys_time& tp, - std::basic_string& abbrev) -{ - return {format, tp, &abbrev}; -} - -template -inline -detail::parse_sys_manip -parse(const std::basic_string& format, sys_time& tp, - std::chrono::minutes& offset) -{ - return {format, tp, nullptr, &offset}; -} - -template -inline -detail::parse_sys_manip -parse(const std::basic_string& format, sys_time& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -detail::parse_sys_manip -parse(const std::basic_string& format, sys_time& tp, - std::chrono::minutes& offset, std::basic_string& abbrev) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -detail::parse_local_manip -parse(const std::basic_string& format, local_time& tp) -{ - return {format, tp}; -} - -template -inline -detail::parse_local_manip -parse(const std::basic_string& format, local_time& tp, - std::basic_string& abbrev) -{ - return {format, tp, &abbrev}; -} - -template -inline -detail::parse_local_manip -parse(const std::basic_string& format, local_time& tp, - std::chrono::minutes& offset) -{ - return {format, tp, nullptr, &offset}; -} - -template -inline -detail::parse_local_manip -parse(const std::basic_string& format, local_time& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -detail::parse_local_manip -parse(const std::basic_string& format, local_time& tp, - std::chrono::minutes& offset, std::basic_string& abbrev) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -detail::parse_duration, CharT, Traits> -parse(const std::basic_string& format, - std::chrono::duration& d) -{ - return {format, d}; -} - #if 0 // use in >> parse(format, x); instead template @@ -6593,106 +6709,6 @@ parse(std::basic_istream& is, detail::parse(is, format.c_str(), tp, &abbrev, &offset); } -#endif // use in >> parse(format, x); instead - -// const CharT* formats - -template -inline -detail::parse_sys_manip -parse(const CharT* format, sys_time& tp) -{ - return {format, tp}; -} - -template -inline -detail::parse_sys_manip -parse(const CharT* format, sys_time& tp, - std::basic_string& abbrev) -{ - return {format, tp, &abbrev}; -} - -template -inline -detail::parse_sys_manip -parse(const CharT* format, sys_time& tp, std::chrono::minutes& offset) -{ - return {format, tp, nullptr, &offset}; -} - -template -inline -detail::parse_sys_manip -parse(const CharT* format, sys_time& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -detail::parse_sys_manip -parse(const CharT* format, sys_time& tp, - std::chrono::minutes& offset, std::basic_string& abbrev) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -detail::parse_local_manip -parse(const CharT* format, local_time& tp) -{ - return {format, tp}; -} - -template -inline -detail::parse_local_manip -parse(const CharT* format, local_time& tp, - std::basic_string& abbrev) -{ - return {format, tp, &abbrev}; -} - -template -inline -detail::parse_local_manip -parse(const CharT* format, local_time& tp, std::chrono::minutes& offset) -{ - return {format, tp, nullptr, &offset}; -} - -template -inline -detail::parse_local_manip -parse(const CharT* format, local_time& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -detail::parse_local_manip -parse(const CharT* format, local_time& tp, std::chrono::minutes& offset, - std::basic_string& abbrev) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -detail::parse_duration, CharT> -parse(const CharT* format, std::chrono::duration& d) -{ - return {format, d}; -} - -#if 0 // use in >> parse(format, x); instead - template inline void @@ -6803,187 +6819,6 @@ parse(std::basic_istream& is, const CharT* format, #endif // use in >> parse(format, x); instead -template -void -to_stream(std::basic_ostream& os, const CharT* fmt, - const year_month_day& ymd) -{ - using CT = std::chrono::seconds; - detail::fields fds{ymd, time_of_day{}}; - detail::to_stream(os, fmt, fds); -} - -template -std::basic_string -format(const std::locale& loc, const CharT* fmt, const year_month_day& ymd) -{ - std::basic_ostringstream os; - os.imbue(loc); - to_stream(os, fmt, ymd); - return os.str(); -} - -template -std::basic_string -format(const CharT* fmt, const year_month_day& ymd) -{ - std::basic_ostringstream os; - to_stream(os, fmt, ymd); - return os.str(); -} - -template -std::basic_string -format(const std::locale& loc, const std::basic_string& fmt, - const year_month_day& ymd) -{ - std::basic_ostringstream os; - os.imbue(loc); - to_stream(os, fmt.c_str(), ymd); - return os.str(); -} - -template -std::basic_string -format(const std::basic_string& fmt, const year_month_day& ymd) -{ - std::basic_ostringstream os; - to_stream(os, fmt.c_str(), ymd); - return os.str(); -} - -namespace detail -{ - -template > -struct parse_ymd_manip -{ - const std::basic_string format_; - year_month_day& ymd_; - std::basic_string* abbrev_; - std::chrono::minutes* offset_; - -public: - parse_ymd_manip(std::basic_string format, - year_month_day& ymd, std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) - : format_(std::move(format)) - , ymd_(ymd) - , abbrev_(abbrev) - , offset_(offset) - {} - -}; - -template -inline -std::basic_istream& -operator>>(std::basic_istream& is, - const parse_ymd_manip& x) -{ - using namespace std; - using namespace std::chrono; - using CT = seconds; - fields fds{}; - parse(is, x.format_.c_str(), fds, x.abbrev_, x.offset_); - if (!fds.ymd.ok()) - is.setstate(ios::failbit); - if (!is.fail()) - x.ymd_ = fds.ymd; - return is; -} - -} // namespace detail - -template -inline -detail::parse_ymd_manip -parse(const std::basic_string& format, year_month_day& ymd) -{ - return {format, ymd}; -} - -template -inline -detail::parse_ymd_manip -parse(const std::basic_string& format, year_month_day& ymd, - std::basic_string& abbrev) -{ - return {format, ymd, &abbrev}; -} - -template -inline -detail::parse_ymd_manip -parse(const std::basic_string& format, year_month_day& ymd, - std::chrono::minutes& offset) -{ - return {format, ymd, nullptr, &offset}; -} - -template -inline -detail::parse_ymd_manip -parse(const std::basic_string& format, year_month_day& ymd, - std::basic_string& abbrev, std::chrono::minutes& offset) -{ - return {format, ymd, &abbrev, &offset}; -} - -template -inline -detail::parse_ymd_manip -parse(const std::basic_string& format, year_month_day& ymd, - std::chrono::minutes& offset, std::basic_string& abbrev) -{ - return {format, ymd, &abbrev, &offset}; -} - -// const CharT* formats - -template -inline -detail::parse_ymd_manip -parse(const CharT* format, year_month_day& ymd) -{ - return {format, ymd}; -} - -template -inline -detail::parse_ymd_manip -parse(const CharT* format, year_month_day& ymd, - std::basic_string& abbrev) -{ - return {format, ymd, &abbrev}; -} - -template -inline -detail::parse_ymd_manip -parse(const CharT* format, year_month_day& ymd, std::chrono::minutes& offset) -{ - return {format, ymd, nullptr, &offset}; -} - -template -inline -detail::parse_ymd_manip -parse(const CharT* format, year_month_day& ymd, - std::basic_string& abbrev, std::chrono::minutes& offset) -{ - return {format, ymd, &abbrev, &offset}; -} - -template -inline -detail::parse_ymd_manip -parse(const CharT* format, year_month_day& ymd, - std::chrono::minutes& offset, std::basic_string& abbrev) -{ - return {format, ymd, &abbrev, &offset}; -} - } // namespace date #endif // DATE_H diff --git a/test/date_test/format/range.pass.cpp b/test/date_test/format/range.pass.cpp index e6e5296..d268b04 100644 --- a/test/date_test/format/range.pass.cpp +++ b/test/date_test/format/range.pass.cpp @@ -67,4 +67,12 @@ main() os.str(""); os << format("%F %T", sys_days{dec/last/year::max()} + microfortnights{1}); assert(os.str() == "32767-12-31 00:00:01.2096"); + os.str(""); + + os << format("%F %T", jan/1/year::min()); + assert(os.str() == "-32768-01-01 00:00:00"); + os.str(""); + os << format("%F %T", dec/last/year::max()); + assert(os.str() == "32767-12-31 00:00:00"); + os.str(""); } diff --git a/test/date_test/parse.pass.cpp b/test/date_test/parse.pass.cpp index aa2be53..89ff4b3 100644 --- a/test/date_test/parse.pass.cpp +++ b/test/date_test/parse.pass.cpp @@ -390,6 +390,14 @@ test_F() assert(!in.bad()); assert(tp == 2016_y/12/13); } + { + std::istringstream in{"2016-12-13"}; + year_month_day tp; + in >> parse("%F", tp); + assert(!in.fail()); + assert(!in.bad()); + assert(tp == 2016_y/12/13); + } } void diff --git a/tz.h b/tz.h index 74adf50..cbb9b54 100644 --- a/tz.h +++ b/tz.h @@ -1036,14 +1036,22 @@ make_zoned(const std::string& name, const sys_time& st) return {name, st}; } +template +void +to_stream(std::basic_ostream& os, const CharT* fmt, + const zoned_time& tp) +{ + auto const info = tp.get_info(); + to_stream(os, fmt, tp.get_local_time(), &info.abbrev, &info.offset); +} + template inline std::basic_ostream& operator<<(std::basic_ostream& os, const zoned_time& t) { - auto i = t.zone_->get_info(t.tp_); - auto lt = t.tp_ + i.offset; - return os << lt << ' ' << i.abbrev; + to_stream(os, "%F %T %Z", t); + return os; } class utc_clock @@ -1138,8 +1146,8 @@ to_stream(std::basic_ostream& os, const CharT* fmt, ymd = sd; time = make_time(tp - sd); time.seconds() += ls; - detail::fields fds{ymd, time}; - detail::to_stream(os, fmt, fds, &abbrev, &offset); + fields fds{ymd, time}; + to_stream(os, fmt, fds, &abbrev, &offset); } template @@ -1150,60 +1158,19 @@ operator<<(std::basic_ostream& os, const utc_time& t) return os; } -template -std::basic_string -format(const std::locale& loc, const CharT* fmt, const utc_time& tp) -{ - std::basic_ostringstream os; - os.imbue(loc); - to_stream(os, fmt, tp); - return os.str(); -} - -template -std::basic_string -format(const CharT* fmt, const utc_time& tp) -{ - std::basic_ostringstream os; - to_stream(os, fmt, tp); - return os.str(); -} - -template -std::basic_string -format(const std::locale& loc, const std::basic_string& fmt, - const utc_time& tp) -{ - std::basic_ostringstream os; - os.imbue(loc); - to_stream(os, fmt.c_str(), tp); - return os.str(); -} - -template -std::basic_string -format(const std::basic_string& fmt, const utc_time& tp) -{ - std::basic_ostringstream os; - to_stream(os, fmt.c_str(), tp); - return os.str(); -} - -namespace detail -{ - -template > -struct parse_utc_manip +template +struct parse_manip, CharT, Traits> { + using type = parse_manip; const std::basic_string format_; utc_time& tp_; std::basic_string* abbrev_; std::chrono::minutes* offset_; public: - parse_utc_manip(std::basic_string format, - utc_time& tp, std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) + parse_manip(std::basic_string format, + utc_time& tp, std::basic_string* abbrev = nullptr, + std::chrono::minutes* offset = nullptr) : format_(std::move(format)) , tp_(tp) , abbrev_(abbrev) @@ -1215,7 +1182,7 @@ public: template std::basic_istream& operator>>(std::basic_istream& is, - const parse_utc_manip& x) + const parse_manip, CharT, Traits>& x) { using namespace std; using namespace std::chrono; @@ -1239,97 +1206,6 @@ operator>>(std::basic_istream& is, return is; } -} // namespace detail - -template -inline -detail::parse_utc_manip -parse(const std::basic_string& format, utc_time& tp) -{ - return {format, tp}; -} - -template -inline -detail::parse_utc_manip -parse(const std::basic_string& format, utc_time& tp, - std::basic_string& abbrev) -{ - return {format, tp, &abbrev}; -} - -template -inline -detail::parse_utc_manip -parse(const std::basic_string& format, utc_time& tp, - std::chrono::minutes& offset) -{ - return {format, tp, nullptr, &offset}; -} - -template -inline -detail::parse_utc_manip -parse(const std::basic_string& format, utc_time& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -detail::parse_utc_manip -parse(const std::basic_string& format, utc_time& tp, - std::chrono::minutes& offset, std::basic_string& abbrev) -{ - return {format, tp, &abbrev, &offset}; -} - -// const CharT* formats - -template -inline -detail::parse_utc_manip -parse(const CharT* format, utc_time& tp) -{ - return {format, tp}; -} - -template -inline -detail::parse_utc_manip -parse(const CharT* format, utc_time& tp, - std::basic_string& abbrev) -{ - return {format, tp, &abbrev}; -} - -template -inline -detail::parse_utc_manip -parse(const CharT* format, utc_time& tp, std::chrono::minutes& offset) -{ - return {format, tp, nullptr, &offset}; -} - -template -inline -detail::parse_utc_manip -parse(const CharT* format, utc_time& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -detail::parse_utc_manip -parse(const CharT* format, utc_time& tp, - std::chrono::minutes& offset, std::basic_string& abbrev) -{ - return {format, tp, &abbrev, &offset}; -} - // tai_clock class tai_clock @@ -1402,8 +1278,8 @@ to_stream(std::basic_ostream& os, const CharT* fmt, auto const sd = floor(tp); year_month_day ymd = sd; auto time = make_time(tp - sd); - detail::fields fds{ymd, time}; - detail::to_stream(os, fmt, fds, &abbrev, &offset); + fields fds{ymd, time}; + to_stream(os, fmt, fds, &abbrev, &offset); } template @@ -1414,60 +1290,19 @@ operator<<(std::basic_ostream& os, const tai_time& t) return os; } -template -std::basic_string -format(const std::locale& loc, const CharT* fmt, const tai_time& tp) -{ - std::basic_ostringstream os; - os.imbue(loc); - to_stream(os, fmt, tp); - return os.str(); -} - -template -std::basic_string -format(const CharT* fmt, const tai_time& tp) -{ - std::basic_ostringstream os; - to_stream(os, fmt, tp); - return os.str(); -} - -template -std::basic_string -format(const std::locale& loc, const std::basic_string& fmt, - const tai_time& tp) -{ - std::basic_ostringstream os; - os.imbue(loc); - to_stream(os, fmt.c_str(), tp); - return os.str(); -} - -template -std::basic_string -format(const std::basic_string& fmt, const tai_time& tp) -{ - std::basic_ostringstream os; - to_stream(os, fmt.c_str(), tp); - return os.str(); -} - -namespace detail -{ - -template > -struct parse_tai_manip +template +struct parse_manip, CharT, Traits> { + using type = parse_manip; const std::basic_string format_; tai_time& tp_; std::basic_string* abbrev_; std::chrono::minutes* offset_; public: - parse_tai_manip(std::basic_string format, - tai_time& tp, std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) + parse_manip(std::basic_string format, + tai_time& tp, std::basic_string* abbrev = nullptr, + std::chrono::minutes* offset = nullptr) : format_(std::move(format)) , tp_(tp) , abbrev_(abbrev) @@ -1479,7 +1314,7 @@ public: template std::basic_istream& operator>>(std::basic_istream& is, - const parse_tai_manip& x) + const parse_manip, CharT, Traits>& x) { using namespace std; using namespace std::chrono; @@ -1497,97 +1332,6 @@ operator>>(std::basic_istream& is, return is; } -} // namespace detail - -template -inline -detail::parse_tai_manip -parse(const std::basic_string& format, tai_time& tp) -{ - return {format, tp}; -} - -template -inline -detail::parse_tai_manip -parse(const std::basic_string& format, tai_time& tp, - std::basic_string& abbrev) -{ - return {format, tp, &abbrev}; -} - -template -inline -detail::parse_tai_manip -parse(const std::basic_string& format, tai_time& tp, - std::chrono::minutes& offset) -{ - return {format, tp, nullptr, &offset}; -} - -template -inline -detail::parse_tai_manip -parse(const std::basic_string& format, tai_time& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -detail::parse_tai_manip -parse(const std::basic_string& format, tai_time& tp, - std::chrono::minutes& offset, std::basic_string& abbrev) -{ - return {format, tp, &abbrev, &offset}; -} - -// const CharT* formats - -template -inline -detail::parse_tai_manip -parse(const CharT* format, tai_time& tp) -{ - return {format, tp}; -} - -template -inline -detail::parse_tai_manip -parse(const CharT* format, tai_time& tp, - std::basic_string& abbrev) -{ - return {format, tp, &abbrev}; -} - -template -inline -detail::parse_tai_manip -parse(const CharT* format, tai_time& tp, std::chrono::minutes& offset) -{ - return {format, tp, nullptr, &offset}; -} - -template -inline -detail::parse_tai_manip -parse(const CharT* format, tai_time& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -detail::parse_tai_manip -parse(const CharT* format, tai_time& tp, - std::chrono::minutes& offset, std::basic_string& abbrev) -{ - return {format, tp, &abbrev, &offset}; -} - // gps_clock class gps_clock @@ -1660,8 +1404,8 @@ to_stream(std::basic_ostream& os, const CharT* fmt, auto const sd = floor(tp); year_month_day ymd = sd; auto time = make_time(tp - sd); - detail::fields fds{ymd, time}; - detail::to_stream(os, fmt, fds, &abbrev, &offset); + fields fds{ymd, time}; + to_stream(os, fmt, fds, &abbrev, &offset); } template @@ -1672,6 +1416,208 @@ operator<<(std::basic_ostream& os, const gps_time& t) return os; } +template +struct parse_manip, CharT, Traits> +{ + using type = parse_manip; + const std::basic_string format_; + gps_time& tp_; + std::basic_string* abbrev_; + std::chrono::minutes* offset_; + +public: + parse_manip(std::basic_string format, + gps_time& tp, std::basic_string* abbrev = nullptr, + std::chrono::minutes* offset = nullptr) + : format_(std::move(format)) + , tp_(tp) + , abbrev_(abbrev) + , offset_(offset) + {} + +}; + +template +std::basic_istream& +operator>>(std::basic_istream& is, + const parse_manip, CharT, Traits>& x) +{ + using namespace std; + using namespace std::chrono; + using CT = typename common_type::type; + minutes offset{}; + auto offptr = x.offset_ ? x.offset_ : &offset; + fields fds{}; + parse(is, x.format_.c_str(), fds, x.abbrev_, offptr); + if (!fds.ymd.ok()) + is.setstate(ios::failbit); + if (!is.fail()) + x.tp_ = gps_time{duration_cast( + (sys_days(fds.ymd) + fds.tod.to_duration() - + (sys_days(year{1980}/jan/sun[1]) - + sys_days(year{1970}/jan/1)) - *offptr).time_since_epoch())}; + return is; +} + +template +inline +sys_time::type> +to_sys_time(const tai_time& t) +{ + return to_sys_time(to_utc_time(t)); +} + +template +inline +sys_time::type> +to_sys_time(const gps_time& t) +{ + return to_sys_time(to_utc_time(t)); +} + +template +inline +tai_time::type> +to_tai_time(const gps_time& t) NOEXCEPT +{ + using namespace std::chrono; + using duration = typename std::common_type::type; + return tai_time{t.time_since_epoch()} + + (sys_days(year{1980}/jan/sun[1]) - sys_days(year{1958}/jan/1) + seconds{19}); +} + +template +inline +gps_time::type> +to_gps_time(const tai_time& t) NOEXCEPT +{ + using namespace std::chrono; + using duration = typename std::common_type::type; + return gps_time{t.time_since_epoch()} - + (sys_days(year{1980}/jan/sun[1]) - sys_days(year{1958}/jan/1) + seconds{19}); +} + +#ifdef NO_EXPRESSION_SFINAE +// format +// basic_string formats + +template +std::basic_string +format(const std::locale& loc, const std::basic_string& fmt, + const zoned_time& tp) +{ + std::basic_ostringstream os; + os.imbue(loc); + to_stream(os, fmt.c_str(), tp); + return os.str(); +} + +template +std::basic_string +format(const std::basic_string& fmt, const zoned_time& tp) +{ + std::basic_ostringstream os; + to_stream(os, fmt.c_str(), tp); + return os.str(); +} + +template +std::basic_string +format(const std::locale& loc, const CharT* fmt, const zoned_time& tp) +{ + std::basic_ostringstream os; + os.imbue(loc); + to_stream(os, fmt, tp); + return os.str(); +} + +template +std::basic_string +format(const CharT* fmt, const zoned_time& tp) +{ + std::basic_ostringstream os; + to_stream(os, fmt, tp); + return os.str(); +} + +template +std::basic_string +format(const std::locale& loc, const CharT* fmt, const utc_time& tp) +{ + std::basic_ostringstream os; + os.imbue(loc); + to_stream(os, fmt, tp); + return os.str(); +} + +template +std::basic_string +format(const CharT* fmt, const utc_time& tp) +{ + std::basic_ostringstream os; + to_stream(os, fmt, tp); + return os.str(); +} + +template +std::basic_string +format(const std::locale& loc, const std::basic_string& fmt, + const utc_time& tp) +{ + std::basic_ostringstream os; + os.imbue(loc); + to_stream(os, fmt.c_str(), tp); + return os.str(); +} + +template +std::basic_string +format(const std::basic_string& fmt, const utc_time& tp) +{ + std::basic_ostringstream os; + to_stream(os, fmt.c_str(), tp); + return os.str(); +} + +template +std::basic_string +format(const std::locale& loc, const CharT* fmt, const tai_time& tp) +{ + std::basic_ostringstream os; + os.imbue(loc); + to_stream(os, fmt, tp); + return os.str(); +} + +template +std::basic_string +format(const CharT* fmt, const tai_time& tp) +{ + std::basic_ostringstream os; + to_stream(os, fmt, tp); + return os.str(); +} + +template +std::basic_string +format(const std::locale& loc, const std::basic_string& fmt, + const tai_time& tp) +{ + std::basic_ostringstream os; + os.imbue(loc); + to_stream(os, fmt.c_str(), tp); + return os.str(); +} + +template +std::basic_string +format(const std::basic_string& fmt, const tai_time& tp) +{ + std::basic_ostringstream os; + to_stream(os, fmt.c_str(), tp); + return os.str(); +} + template std::basic_string format(const std::locale& loc, const CharT* fmt, const gps_time& tp) @@ -1711,233 +1657,7 @@ format(const std::basic_string& fmt, const gps_time& tp return os.str(); } -namespace detail -{ - -template > -struct parse_gps_manip -{ - const std::basic_string format_; - gps_time& tp_; - std::basic_string* abbrev_; - std::chrono::minutes* offset_; - -public: - parse_gps_manip(std::basic_string format, - gps_time& tp, std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) - : format_(std::move(format)) - , tp_(tp) - , abbrev_(abbrev) - , offset_(offset) - {} - -}; - -template -std::basic_istream& -operator>>(std::basic_istream& is, - const parse_gps_manip& x) -{ - using namespace std; - using namespace std::chrono; - using CT = typename common_type::type; - minutes offset{}; - auto offptr = x.offset_ ? x.offset_ : &offset; - fields fds{}; - parse(is, x.format_.c_str(), fds, x.abbrev_, offptr); - if (!fds.ymd.ok()) - is.setstate(ios::failbit); - if (!is.fail()) - x.tp_ = gps_time{duration_cast( - (sys_days(fds.ymd) + fds.tod.to_duration() - - (sys_days(year{1980}/jan/sun[1]) - - sys_days(year{1970}/jan/1)) - *offptr).time_since_epoch())}; - return is; -} - -} // namespace detail - -template -inline -detail::parse_gps_manip -parse(const std::basic_string& format, gps_time& tp) -{ - return {format, tp}; -} - -template -inline -detail::parse_gps_manip -parse(const std::basic_string& format, gps_time& tp, - std::basic_string& abbrev) -{ - return {format, tp, &abbrev}; -} - -template -inline -detail::parse_gps_manip -parse(const std::basic_string& format, gps_time& tp, - std::chrono::minutes& offset) -{ - return {format, tp, nullptr, &offset}; -} - -template -inline -detail::parse_gps_manip -parse(const std::basic_string& format, gps_time& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -detail::parse_gps_manip -parse(const std::basic_string& format, gps_time& tp, - std::chrono::minutes& offset, std::basic_string& abbrev) -{ - return {format, tp, &abbrev, &offset}; -} - -// const CharT* formats - -template -inline -detail::parse_gps_manip -parse(const CharT* format, gps_time& tp) -{ - return {format, tp}; -} - -template -inline -detail::parse_gps_manip -parse(const CharT* format, gps_time& tp, - std::basic_string& abbrev) -{ - return {format, tp, &abbrev}; -} - -template -inline -detail::parse_gps_manip -parse(const CharT* format, gps_time& tp, std::chrono::minutes& offset) -{ - return {format, tp, nullptr, &offset}; -} - -template -inline -detail::parse_gps_manip -parse(const CharT* format, gps_time& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -detail::parse_gps_manip -parse(const CharT* format, gps_time& tp, - std::chrono::minutes& offset, std::basic_string& abbrev) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -sys_time::type> -to_sys_time(const tai_time& t) -{ - return to_sys_time(to_utc_time(t)); -} - -template -inline -sys_time::type> -to_sys_time(const gps_time& t) -{ - return to_sys_time(to_utc_time(t)); -} - -template -inline -tai_time::type> -to_tai_time(const gps_time& t) NOEXCEPT -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - return tai_time{t.time_since_epoch()} + - (sys_days(year{1980}/jan/sun[1]) - sys_days(year{1958}/jan/1) + seconds{19}); -} - -template -inline -gps_time::type> -to_gps_time(const tai_time& t) NOEXCEPT -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - return gps_time{t.time_since_epoch()} - - (sys_days(year{1980}/jan/sun[1]) - sys_days(year{1958}/jan/1) + seconds{19}); -} - -// format - -template -void -to_stream(std::basic_ostream& os, const CharT* fmt, - const zoned_time& tp) -{ - auto const info = tp.get_info(); - to_stream(os, fmt, tp.get_local_time(), &info.abbrev, &info.offset); -} - -// basic_string formats - -template -std::basic_string -format(const std::locale& loc, const std::basic_string& fmt, - const zoned_time& tp) -{ - std::basic_ostringstream os; - os.imbue(loc); - to_stream(os, fmt.c_str(), tp); - return os.str(); -} - -template -std::basic_string -format(const std::basic_string& fmt, const zoned_time& tp) -{ - std::basic_ostringstream os; - to_stream(os, fmt.c_str(), tp); - return os.str(); -} - -// const CharT* formats - -template -std::basic_string -format(const std::locale& loc, const CharT* fmt, const zoned_time& tp) -{ - std::basic_ostringstream os; - os.imbue(loc); - to_stream(os, fmt, tp); - return os.str(); -} - -template -std::basic_string -format(const CharT* fmt, const zoned_time& tp) -{ - std::basic_ostringstream os; - to_stream(os, fmt, tp); - return os.str(); -} +#endif // NO_EXPRESSION_SFINAE } // namespace date