1 | // -*- C++ -*- |
2 | //===----------------------------------------------------------------------===// |
3 | // |
4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
5 | // See https://llvm.org/LICENSE.txt for license information. |
6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
7 | // |
8 | //===----------------------------------------------------------------------===// |
9 | |
10 | #ifndef _LIBCPP___CHRONO_OSTREAM_H |
11 | #define _LIBCPP___CHRONO_OSTREAM_H |
12 | |
13 | #include <__chrono/calendar.h> |
14 | #include <__chrono/day.h> |
15 | #include <__chrono/duration.h> |
16 | #include <__chrono/file_clock.h> |
17 | #include <__chrono/hh_mm_ss.h> |
18 | #include <__chrono/local_info.h> |
19 | #include <__chrono/month.h> |
20 | #include <__chrono/month_weekday.h> |
21 | #include <__chrono/monthday.h> |
22 | #include <__chrono/statically_widen.h> |
23 | #include <__chrono/sys_info.h> |
24 | #include <__chrono/system_clock.h> |
25 | #include <__chrono/weekday.h> |
26 | #include <__chrono/year.h> |
27 | #include <__chrono/year_month.h> |
28 | #include <__chrono/year_month_day.h> |
29 | #include <__chrono/year_month_weekday.h> |
30 | #include <__chrono/zoned_time.h> |
31 | #include <__concepts/same_as.h> |
32 | #include <__config> |
33 | #include <__format/format_functions.h> |
34 | #include <__fwd/ostream.h> |
35 | #include <ratio> |
36 | |
37 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
38 | # pragma GCC system_header |
39 | #endif |
40 | |
41 | _LIBCPP_BEGIN_NAMESPACE_STD |
42 | |
43 | #if _LIBCPP_STD_VER >= 20 |
44 | |
45 | namespace chrono { |
46 | |
47 | template <class _CharT, class _Traits, class _Duration> |
48 | requires(!treat_as_floating_point_v<typename _Duration::rep> && _Duration{1} < days{1}) |
49 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
50 | operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_time<_Duration>& __tp) { |
51 | return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}" ), __tp); |
52 | } |
53 | |
54 | template <class _CharT, class _Traits> |
55 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
56 | operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_days& __dp) { |
57 | return __os << year_month_day{__dp}; |
58 | } |
59 | |
60 | template <class _CharT, class _Traits, class _Duration> |
61 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
62 | operator<<(basic_ostream<_CharT, _Traits>& __os, const file_time<_Duration> __tp) { |
63 | return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}" ), __tp); |
64 | } |
65 | |
66 | template <class _CharT, class _Traits, class _Duration> |
67 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
68 | operator<<(basic_ostream<_CharT, _Traits>& __os, const local_time<_Duration> __tp) { |
69 | return __os << sys_time<_Duration>{__tp.time_since_epoch()}; |
70 | } |
71 | |
72 | // Depending on the type the return is a const _CharT* or a basic_string<_CharT> |
73 | template <class _CharT, class _Period> |
74 | _LIBCPP_HIDE_FROM_ABI auto __units_suffix() { |
75 | // TODO FMT LWG issue the suffixes are always char and not STATICALLY-WIDEN'ed. |
76 | if constexpr (same_as<typename _Period::type, atto>) |
77 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "as" ); |
78 | else if constexpr (same_as<typename _Period::type, femto>) |
79 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "fs" ); |
80 | else if constexpr (same_as<typename _Period::type, pico>) |
81 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "ps" ); |
82 | else if constexpr (same_as<typename _Period::type, nano>) |
83 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "ns" ); |
84 | else if constexpr (same_as<typename _Period::type, micro>) |
85 | # ifndef _LIBCPP_HAS_NO_UNICODE |
86 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "\u00b5s" ); |
87 | # else |
88 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "us" ); |
89 | # endif |
90 | else if constexpr (same_as<typename _Period::type, milli>) |
91 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "ms" ); |
92 | else if constexpr (same_as<typename _Period::type, centi>) |
93 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "cs" ); |
94 | else if constexpr (same_as<typename _Period::type, deci>) |
95 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "ds" ); |
96 | else if constexpr (same_as<typename _Period::type, ratio<1>>) |
97 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "s" ); |
98 | else if constexpr (same_as<typename _Period::type, deca>) |
99 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "das" ); |
100 | else if constexpr (same_as<typename _Period::type, hecto>) |
101 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "hs" ); |
102 | else if constexpr (same_as<typename _Period::type, kilo>) |
103 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "ks" ); |
104 | else if constexpr (same_as<typename _Period::type, mega>) |
105 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "Ms" ); |
106 | else if constexpr (same_as<typename _Period::type, giga>) |
107 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "Gs" ); |
108 | else if constexpr (same_as<typename _Period::type, tera>) |
109 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "Ts" ); |
110 | else if constexpr (same_as<typename _Period::type, peta>) |
111 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "Ps" ); |
112 | else if constexpr (same_as<typename _Period::type, exa>) |
113 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "Es" ); |
114 | else if constexpr (same_as<typename _Period::type, ratio<60>>) |
115 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "min" ); |
116 | else if constexpr (same_as<typename _Period::type, ratio<3600>>) |
117 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "h" ); |
118 | else if constexpr (same_as<typename _Period::type, ratio<86400>>) |
119 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "d" ); |
120 | else if constexpr (_Period::den == 1) |
121 | return std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "[{}]s" ), _Period::num); |
122 | else |
123 | return std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "[{}/{}]s" ), _Period::num, _Period::den); |
124 | } |
125 | |
126 | template <class _CharT, class _Traits, class _Rep, class _Period> |
127 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
128 | operator<<(basic_ostream<_CharT, _Traits>& __os, const duration<_Rep, _Period>& __d) { |
129 | basic_ostringstream<_CharT, _Traits> __s; |
130 | __s.flags(__os.flags()); |
131 | __s.imbue(__os.getloc()); |
132 | __s.precision(__os.precision()); |
133 | __s << __d.count() << chrono::__units_suffix<_CharT, _Period>(); |
134 | return __os << __s.str(); |
135 | } |
136 | |
137 | template <class _CharT, class _Traits> |
138 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& __os, const day& __d) { |
139 | return __os << (__d.ok() ? std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:%d}" ), __d) |
140 | // Note this error differs from the wording of the Standard. The |
141 | // Standard wording doesn't work well on AIX or Windows. There |
142 | // the formatted day seems to be either modulo 100 or completely |
143 | // omitted. Judging by the wording this is valid. |
144 | // TODO FMT Write a paper of file an LWG issue. |
145 | : std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:02} is not a valid day" ), |
146 | static_cast<unsigned>(__d))); |
147 | } |
148 | |
149 | template <class _CharT, class _Traits> |
150 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
151 | operator<<(basic_ostream<_CharT, _Traits>& __os, const month& __m) { |
152 | return __os << (__m.ok() ? std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%b}" ), __m) |
153 | : std::format(__os.getloc(), |
154 | _LIBCPP_STATICALLY_WIDEN(_CharT, "{} is not a valid month" ), |
155 | static_cast<unsigned>(__m))); // TODO FMT Standard mandated locale isn't used. |
156 | } |
157 | |
158 | template <class _CharT, class _Traits> |
159 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
160 | operator<<(basic_ostream<_CharT, _Traits>& __os, const year& __y) { |
161 | return __os << (__y.ok() ? std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:%Y}" ), __y) |
162 | : std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:%Y} is not a valid year" ), __y)); |
163 | } |
164 | |
165 | template <class _CharT, class _Traits> |
166 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
167 | operator<<(basic_ostream<_CharT, _Traits>& __os, const weekday& __wd) { |
168 | return __os << (__wd.ok() ? std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%a}" ), __wd) |
169 | : std::format(__os.getloc(), // TODO FMT Standard mandated locale isn't used. |
170 | _LIBCPP_STATICALLY_WIDEN(_CharT, "{} is not a valid weekday" ), |
171 | static_cast<unsigned>(__wd.c_encoding()))); |
172 | } |
173 | |
174 | template <class _CharT, class _Traits> |
175 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
176 | operator<<(basic_ostream<_CharT, _Traits>& __os, const weekday_indexed& __wdi) { |
177 | auto __i = __wdi.index(); |
178 | return __os << (__i >= 1 && __i <= 5 |
179 | ? std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}[{}]" ), __wdi.weekday(), __i) |
180 | : std::format(__os.getloc(), |
181 | _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}[{} is not a valid index]" ), |
182 | __wdi.weekday(), |
183 | __i)); |
184 | } |
185 | |
186 | template <class _CharT, class _Traits> |
187 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
188 | operator<<(basic_ostream<_CharT, _Traits>& __os, const weekday_last& __wdl) { |
189 | return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}[last]" ), __wdl.weekday()); |
190 | } |
191 | |
192 | template <class _CharT, class _Traits> |
193 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
194 | operator<<(basic_ostream<_CharT, _Traits>& __os, const month_day& __md) { |
195 | // TODO FMT The Standard allows 30th of February to be printed. |
196 | // It would be nice to show an error message instead. |
197 | return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}/{}" ), __md.month(), __md.day()); |
198 | } |
199 | |
200 | template <class _CharT, class _Traits> |
201 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
202 | operator<<(basic_ostream<_CharT, _Traits>& __os, const month_day_last& __mdl) { |
203 | return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}/last" ), __mdl.month()); |
204 | } |
205 | |
206 | template <class _CharT, class _Traits> |
207 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
208 | operator<<(basic_ostream<_CharT, _Traits>& __os, const month_weekday& __mwd) { |
209 | return __os << std::format( |
210 | __os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}/{:L}" ), __mwd.month(), __mwd.weekday_indexed()); |
211 | } |
212 | |
213 | template <class _CharT, class _Traits> |
214 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
215 | operator<<(basic_ostream<_CharT, _Traits>& __os, const month_weekday_last& __mwdl) { |
216 | return __os << std::format( |
217 | __os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L}/{:L}" ), __mwdl.month(), __mwdl.weekday_last()); |
218 | } |
219 | |
220 | template <class _CharT, class _Traits> |
221 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
222 | operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month& __ym) { |
223 | return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{}/{:L}" ), __ym.year(), __ym.month()); |
224 | } |
225 | |
226 | template <class _CharT, class _Traits> |
227 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
228 | operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month_day& __ymd) { |
229 | return __os << (__ymd.ok() ? std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:%F}" ), __ymd) |
230 | : std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:%F} is not a valid date" ), __ymd)); |
231 | } |
232 | |
233 | template <class _CharT, class _Traits> |
234 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
235 | operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month_day_last& __ymdl) { |
236 | return __os << std::format( |
237 | __os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{}/{:L}" ), __ymdl.year(), __ymdl.month_day_last()); |
238 | } |
239 | |
240 | template <class _CharT, class _Traits> |
241 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
242 | operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month_weekday& __ymwd) { |
243 | return __os << std::format( |
244 | __os.getloc(), |
245 | _LIBCPP_STATICALLY_WIDEN(_CharT, "{}/{:L}/{:L}" ), |
246 | __ymwd.year(), |
247 | __ymwd.month(), |
248 | __ymwd.weekday_indexed()); |
249 | } |
250 | |
251 | template <class _CharT, class _Traits> |
252 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
253 | operator<<(basic_ostream<_CharT, _Traits>& __os, const year_month_weekday_last& __ymwdl) { |
254 | return __os << std::format( |
255 | __os.getloc(), |
256 | _LIBCPP_STATICALLY_WIDEN(_CharT, "{}/{:L}/{:L}" ), |
257 | __ymwdl.year(), |
258 | __ymwdl.month(), |
259 | __ymwdl.weekday_last()); |
260 | } |
261 | |
262 | template <class _CharT, class _Traits, class _Duration> |
263 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
264 | operator<<(basic_ostream<_CharT, _Traits>& __os, const hh_mm_ss<_Duration> __hms) { |
265 | return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%T}" ), __hms); |
266 | } |
267 | |
268 | # if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) |
269 | |
270 | template <class _CharT, class _Traits> |
271 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
272 | operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_info& __info) { |
273 | // __info.abbrev is always std::basic_string<char>. |
274 | // Since these strings typically are short the conversion should be cheap. |
275 | std::basic_string<_CharT> __abbrev{__info.abbrev.begin(), __info.abbrev.end()}; |
276 | return __os << std::format( |
277 | _LIBCPP_STATICALLY_WIDEN(_CharT, "[{:%F %T}, {:%F %T}) {:%T} {:%Q%q} \"{}\"" ), |
278 | __info.begin, |
279 | __info.end, |
280 | hh_mm_ss{__info.offset}, |
281 | __info.save, |
282 | __abbrev); |
283 | } |
284 | |
285 | template <class _CharT, class _Traits> |
286 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
287 | operator<<(basic_ostream<_CharT, _Traits>& __os, const local_info& __info) { |
288 | auto __result = [&]() -> basic_string<_CharT> { |
289 | switch (__info.result) { |
290 | case local_info::unique: |
291 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "unique" ); |
292 | case local_info::nonexistent: |
293 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "non-existent" ); |
294 | case local_info::ambiguous: |
295 | return _LIBCPP_STATICALLY_WIDEN(_CharT, "ambiguous" ); |
296 | |
297 | default: |
298 | return std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "unspecified result ({})" ), __info.result); |
299 | }; |
300 | }; |
301 | |
302 | return __os << std::format( |
303 | _LIBCPP_STATICALLY_WIDEN(_CharT, "{}: {{{}, {}}}" ), __result(), __info.first, __info.second); |
304 | } |
305 | |
306 | # if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \ |
307 | !defined(_LIBCPP_HAS_NO_LOCALIZATION) |
308 | template <class _CharT, class _Traits, class _Duration, class _TimeZonePtr> |
309 | _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& |
310 | operator<<(basic_ostream<_CharT, _Traits>& __os, const zoned_time<_Duration, _TimeZonePtr>& __tp) { |
311 | return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T %Z}" ), __tp); |
312 | } |
313 | # endif |
314 | # endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB) |
315 | |
316 | } // namespace chrono |
317 | |
318 | #endif // if _LIBCPP_STD_VER >= 20 |
319 | |
320 | _LIBCPP_END_NAMESPACE_STD |
321 | |
322 | #endif // _LIBCPP___CHRONO_OSTREAM_H |
323 | |