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