@@ -93,6 +93,50 @@ TString DateToString(time_t when, long* sec = nullptr);
93
93
TString YearToString (const struct tm & theTm);
94
94
TString YearToString (time_t when);
95
95
96
+ namespace NDateTimeHelpers {
97
+ template <typename T>
98
+ struct TPrecisionHelper {
99
+ using THighPrecision = ui64;
100
+ };
101
+
102
+ template <>
103
+ struct TPrecisionHelper <float > {
104
+ using THighPrecision = double ;
105
+ };
106
+
107
+ template <>
108
+ struct TPrecisionHelper <double > {
109
+ using THighPrecision = double ;
110
+ };
111
+
112
+ template <ui64 b, typename T>
113
+ static constexpr ui64 MulWithSaturation (T a) = delete;
114
+
115
+ template <ui64 b>
116
+ constexpr ui64 MulWithSaturation (ui64 a) {
117
+ constexpr ui64 maxMultiplicand = Max<ui64>() / b;
118
+ #if defined(__GNUC__) && defined(__cpp_lib_is_constant_evaluated)
119
+ if (!std::is_constant_evaluated ()) {
120
+ if constexpr (std::is_same<ui64, unsigned long >::value) {
121
+ unsigned long r = 0 ;
122
+ return __builtin_umull_overflow (a, b, &r) ? Max<ui64>() : r;
123
+ }
124
+ if constexpr (std::is_same<ui64, unsigned long long >::value) {
125
+ unsigned long long r = 0 ;
126
+ return __builtin_umulll_overflow (a, b, &r) ? Max<ui64>() : r;
127
+ }
128
+ }
129
+ #endif
130
+ return a <= maxMultiplicand ? a * b : Max<ui64>();
131
+ }
132
+
133
+ template <ui64 b>
134
+ constexpr ui64 MulWithSaturation (double a) {
135
+ double r = a * b;
136
+ return r < 0 ? 0 : (r <= MaxFloor<ui64>() ? static_cast <ui64>(r) : Max<ui64>());
137
+ }
138
+ } // namespace NDateTimeHelpers
139
+
96
140
template <class S >
97
141
class TTimeBase {
98
142
public:
@@ -172,25 +216,32 @@ class TTimeBase {
172
216
}
173
217
174
218
protected:
175
- TValue Value_; // microseconds count
176
- };
219
+ /* noexcept(false) as conversion from T might throw, for example FromString("abc") */
220
+ template <typename T>
221
+ static constexpr S MilliSecondsConvertFrom (T milliseconds) noexcept (false ) {
222
+ auto ms = typename NDateTimeHelpers::TPrecisionHelper<T>::THighPrecision (milliseconds);
223
+ return S::MicroSeconds (NDateTimeHelpers::MulWithSaturation<ui64 (1'000 )>(ms));
224
+ }
177
225
178
- namespace NDateTimeHelpers {
226
+ /* noexcept(false) as conversion from T might throw, for example FromString("abc") */
179
227
template <typename T>
180
- struct TPrecisionHelper {
181
- using THighPrecision = ui64;
182
- };
228
+ static constexpr S SecondsConvertFrom (T seconds) noexcept (false ) {
229
+ auto s = typename NDateTimeHelpers::TPrecisionHelper<T>::THighPrecision (seconds);
230
+ if constexpr (std::is_same_v<decltype (s), double >) {
231
+ return MilliSecondsConvertFrom (s * 1000 );
232
+ }
233
+ return S::MicroSeconds (NDateTimeHelpers::MulWithSaturation<ui64 (1'000'000 )>(s));
234
+ }
183
235
184
- template <>
185
- struct TPrecisionHelper <float > {
186
- using THighPrecision = double ;
187
- };
236
+ static constexpr S Minutes (ui64 m) noexcept ;
188
237
189
- template <>
190
- struct TPrecisionHelper <double > {
191
- using THighPrecision = double ;
192
- };
193
- } // namespace NDateTimeHelpers
238
+ static constexpr S Hours (ui64 h) noexcept ;
239
+
240
+ static constexpr S Days (ui64 d) noexcept ;
241
+
242
+ protected:
243
+ TValue Value_; // microseconds count
244
+ };
194
245
195
246
class TDuration : public TTimeBase <TDuration> {
196
247
using TBase = TTimeBase<TDuration>;
@@ -267,7 +318,7 @@ class TDuration: public TTimeBase<TDuration> {
267
318
/* noexcept(false) as conversion from T might throw, for example FromString("abc") */
268
319
template <typename T>
269
320
static constexpr TDuration MilliSeconds (T ms) noexcept (false ) {
270
- return MicroSeconds ((ui64)( typename NDateTimeHelpers::TPrecisionHelper<T>:: THighPrecision (ms) * 1000 ));
321
+ return TBase::MilliSecondsConvertFrom ( std::move (ms));
271
322
}
272
323
273
324
using TBase::Days;
@@ -277,6 +328,12 @@ class TDuration: public TTimeBase<TDuration> {
277
328
using TBase::Minutes;
278
329
using TBase::Seconds;
279
330
331
+ // / Base class static methods:
332
+ // /
333
+ // / static constexpr TDuration Minutes(ui64 m) noexcept;
334
+ // / static constexpr TDuration Hours(ui64 h) noexcept;
335
+ // / static constexpr TDuration Days(ui64 d) noexcept;
336
+
280
337
// / DeadLineFromTimeOut
281
338
inline TInstant ToDeadLine () const ;
282
339
constexpr TInstant ToDeadLine (TInstant now) const ;
@@ -292,19 +349,7 @@ class TDuration: public TTimeBase<TDuration> {
292
349
/* noexcept(false) as conversion from T might throw, for example FromString("abc") */
293
350
template <typename T>
294
351
static constexpr TDuration Seconds (T s) noexcept (false ) {
295
- return MilliSeconds (typename NDateTimeHelpers::TPrecisionHelper<T>::THighPrecision (s) * 1000 );
296
- }
297
-
298
- static constexpr TDuration Minutes (ui64 m) noexcept {
299
- return Seconds (m * 60 );
300
- }
301
-
302
- static constexpr TDuration Hours (ui64 h) noexcept {
303
- return Minutes (h * 60 );
304
- }
305
-
306
- static constexpr TDuration Days (ui64 d) noexcept {
307
- return Hours (d * 24 );
352
+ return TBase::SecondsConvertFrom (std::move (s));
308
353
}
309
354
310
355
// / parses strings like 10s, 15ms, 15.05s, 20us, or just 25 (s). See parser_ut.cpp for details
@@ -396,30 +441,26 @@ class TInstant: public TTimeBase<TInstant> {
396
441
return TInstant (us);
397
442
}
398
443
399
- // / ms since epoch
444
+ // / milliseconds since epoch
400
445
static constexpr TInstant MilliSeconds (ui64 ms) noexcept {
401
- return MicroSeconds (ms * 1000 );
446
+ return TBase::MilliSecondsConvertFrom (ms);
402
447
}
403
448
404
449
// / seconds since epoch
405
450
static constexpr TInstant Seconds (ui64 s) noexcept {
406
- return MilliSeconds (s * 1000 );
451
+ return TBase::SecondsConvertFrom (s );
407
452
}
408
453
454
+ // / Base class static methods:
455
+ // /
409
456
// / minutes since epoch
410
- static constexpr TInstant Minutes (ui64 m) noexcept {
411
- return Seconds (m * 60 );
412
- }
413
-
457
+ // / static constexpr TInstant Minutes(ui64 m) noexcept;
458
+ // /
414
459
// / hours since epoch
415
- static constexpr TInstant Hours (ui64 h) noexcept {
416
- return Minutes (h * 60 );
417
- }
418
-
460
+ // / static constexpr TInstant Hours(ui64 h) noexcept;
461
+ // /
419
462
// / days since epoch
420
- static constexpr TInstant Days (ui64 d) noexcept {
421
- return Hours (d * 24 );
422
- }
463
+ // / static constexpr TInstant Days(ui64 d) noexcept;
423
464
424
465
constexpr time_t TimeT () const noexcept {
425
466
return (time_t )Seconds ();
@@ -818,6 +859,21 @@ static inline TInstant Now() noexcept {
818
859
return TInstant::Now ();
819
860
}
820
861
862
+ template <class S >
863
+ constexpr S TTimeBase<S>::Minutes(ui64 m) noexcept {
864
+ return S::MicroSeconds (NDateTimeHelpers::MulWithSaturation<ui64 (1'000'000 ) * 60 >(m));
865
+ }
866
+
867
+ template <class S >
868
+ constexpr S TTimeBase<S>::Hours(ui64 h) noexcept {
869
+ return S::MicroSeconds (NDateTimeHelpers::MulWithSaturation<ui64 (1'000'000 ) * 60 * 60 >(h));
870
+ }
871
+
872
+ template <class S >
873
+ constexpr S TTimeBase<S>::Days(ui64 d) noexcept {
874
+ return S::MicroSeconds (NDateTimeHelpers::MulWithSaturation<ui64 (1'000'000 ) * 60 * 60 * 24 >(d));
875
+ }
876
+
821
877
#ifdef _MSC_VER
822
878
#pragma warning(pop)
823
879
#endif // _MSC_VER
0 commit comments