Stroika Library 3.0d18
 
Loading...
Searching...
No Matches
Duration.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include <limits>
5
6namespace Stroika::Foundation::Time {
7
8 /*
9 ********************************************************************************
10 ************************************ Duration **********************************
11 ********************************************************************************
12 */
13 template <typename DURATION_REP, typename DURATION_PERIOD>
14 constexpr Duration::Duration (const chrono::duration<DURATION_REP, DURATION_PERIOD>& d)
15 : inherited{chrono::duration<InternalNumericFormatType_> (d).count ()}
16 , fRepType_{eNumeric_}
17 , fNonStringRep_{}
18 {
19 if (not is_constant_evaluated ()) {
20 if constexpr (floating_point<DURATION_REP>) {
21 Require (not isnan (d.count ())); // inf is allowed, isnan not yet constexpr as of c++20, fixed in c++23
22 }
23 }
24 }
25 constexpr Duration::Duration ()
26 : inherited{kValueWhenEmptyRenderedAsNumber_}
27 , fRepType_{eEmpty_}
28 , fNonStringRep_{}
29 {
30 }
31 inline Duration::Duration (const Duration& src)
32 : inherited{src}
33 , fRepType_{src.fRepType_}
34 {
35 if (fRepType_ == eString_) {
36 Assert (not src.fStringRep_.empty ());
37 new (&fStringRep_) string{src.fStringRep_};
38 }
39 }
40 inline Duration::Duration (Duration&& src) noexcept
41 : inherited{move (src)}
42 , fRepType_{src.fRepType_}
43 {
44 if (src.fRepType_ == eString_) {
45 Assert (fRepType_ == eString_);
46 new (&fStringRep_) string{move (src.fStringRep_)};
47 }
48 src.fRepType_ = eEmpty_;
49 }
50 template <Characters::IConvertibleToString STRINGISH_T>
51 inline Duration::Duration (STRINGISH_T&& durationStr)
52 : inherited{kValueWhenEmptyRenderedAsNumber_}
53 , fNonStringRep_{}
54 {
55 Assert (fRepType_ == eEmpty_);
56 string asciiRep;
57 if constexpr (same_as<STRINGISH_T, string>) {
58 asciiRep = durationStr;
59 }
60 else {
61 asciiRep = Characters::String{durationStr}.AsASCII ();
62 }
63 if (not asciiRep.empty ()) {
64 (*(inherited*)this) = inherited{ParseTime_ (asciiRep)};
65 new (&fStringRep_) string{asciiRep};
66 fRepType_ = eString_;
67 }
68 }
69 constexpr Duration::Duration (int durationInSeconds)
70 : inherited{durationInSeconds}
71 , fRepType_{eNumeric_}
72 , fNonStringRep_{}
73 {
74 }
75 constexpr Duration::Duration (long durationInSeconds)
76 : inherited{durationInSeconds}
77 , fRepType_{eNumeric_}
78 , fNonStringRep_{}
79 {
80 }
81 constexpr Duration::Duration (long long durationInSeconds)
82 : inherited{static_cast<InternalNumericFormatType_> (durationInSeconds)}
83 , fRepType_{eNumeric_}
84 , fNonStringRep_{}
85 {
86 }
87 constexpr Duration::Duration (float durationInSeconds)
88 : inherited{durationInSeconds}
89 , fRepType_{eNumeric_}
90 , fNonStringRep_{}
91 {
92 if (not is_constant_evaluated ()) {
93 Require (not isnan (durationInSeconds)); // inf is allowed, isnan not yet constexpr as of c++20, fixed in c++23
94 }
95 }
96 constexpr Duration::Duration (double durationInSeconds)
97 : inherited{durationInSeconds}
98 , fRepType_{eNumeric_}
99 , fNonStringRep_{}
100 {
101 if (not is_constant_evaluated ()) {
102 Require (not isnan (durationInSeconds)); // inf is allowed, isnan not yet constexpr as of c++20, fixed in c++23
103 }
104 }
105 constexpr Duration::Duration (long double durationInSeconds) noexcept
106 : inherited{static_cast<InternalNumericFormatType_> (durationInSeconds)}
107 , fRepType_{eNumeric_}
108 , fNonStringRep_{}
109 {
110 if (not is_constant_evaluated ()) {
111 Require (not isnan (durationInSeconds)); // inf is allowed, isnan not yet constexpr as of c++20, fixed in c++23
112 }
113 }
114 inline u8string Duration::AsUTF8 () const
115 {
116 return As<Characters::String> ().AsUTF8 ();
117 }
118 inline constexpr Duration::~Duration ()
119 {
120 destroy_ ();
121 }
122 inline void Duration::clear ()
123 {
124 destroy_ ();
125 }
126 constexpr bool Duration::empty () const
127 {
128 // on construction with an empty string, this produces type eEmpty_
129 return fRepType_ == eEmpty_;
130 }
131 inline Duration& Duration::operator= (const Duration& rhs)
132 {
133 if (this != &rhs) {
134 if (fRepType_ == rhs.fRepType_) {
135 if (rhs.fRepType_ == eString_) {
136 // if both unions have string active - just assign
137 fStringRep_ = rhs.fStringRep_;
138 }
139 }
140 else {
141 // if reps different, destroy in case this is string type
142 destroy_ ();
143 if (rhs.fRepType_ == eString_) {
144 new (&fStringRep_) string{rhs.fStringRep_};
145 // fRepType_ = eString_; done at end of procedure
146 }
147 }
148 inherited::operator= (rhs);
149 fRepType_ = rhs.fRepType_;
150 }
151 return *this;
152 }
153 inline Duration& Duration::operator= (Duration&& rhs) noexcept
154 {
155 if (this != &rhs) {
156 if (fRepType_ == rhs.fRepType_) {
157 // if both unions have string active - just move assign
158 if (rhs.fRepType_ == eString_) {
159 fStringRep_ = move (rhs.fStringRep_);
160 // setting our type, and STEALING type of rhs at bottom of procedure
161 }
162 }
163 else {
164 // if reps different, destroy in case this is string type
165 destroy_ ();
166 if (rhs.fRepType_ == eString_) {
167 new (&fStringRep_) string{move (rhs.fStringRep_)};
168 }
169 }
170 inherited::operator= (move (rhs));
171 fRepType_ = rhs.fRepType_;
172 rhs.fRepType_ = eEmpty_;
173 }
174 return *this;
175 }
176 inline constexpr void Duration::destroy_ ()
177 {
178 if (fRepType_ == eString_) {
179 fStringRep_.~basic_string ();
180 }
181 fRepType_ = eEmpty_;
182 }
183 template <typename T>
184 inline T Duration::As () const
185 requires (Common::IAnyOf<T, timeval, Characters::String> or integral<T> or floating_point<T> or Common::IDuration<T> or Common::ITimePoint<T>)
186 {
187 if constexpr (integral<T> or floating_point<T>) {
188 return static_cast<T> (count ());
189 }
190 else if constexpr (same_as<T, timeval>) {
191 rep r = count (); // @todo fix for negative case
192 decltype (timeval::tv_sec) seconds = static_cast<long> (r);
193 r -= seconds;
194 return timeval{seconds, static_cast<decltype (timeval::tv_usec)> (r * 1000 * 1000)};
195 }
196 else if constexpr (same_as<T, Characters::String>) {
197 using Characters::String;
198 switch (fRepType_) {
199 case eEmpty_:
200 return String{};
201 case eString_:
202 return String{fStringRep_};
203 case eNumeric_:
204 return UnParseTime_ (count (), Characters::FloatConversion::Precision{}); // new behavior as of v3.0d12 - default precision instead of full
205 }
207 return String{};
208 }
209 else if constexpr (Common::IDuration<T>) {
210 return chrono::duration_cast<T> (*this);
211 }
212 else if constexpr (Common::ITimePoint<T>) {
213 return T{this->As<typename T::duration> ()};
214 }
215 }
216 template <typename T>
217 inline T Duration::As (Characters::FloatConversion::Precision p) const
218 requires (Common::IAnyOf<T, Characters::String>)
219 {
220 if constexpr (same_as<T, Characters::String>) {
221 using Characters::String;
222 switch (fRepType_) {
223 case eEmpty_:
224 return String{};
225 case eString_: // unclear about this case? -- different answer than with no argument precision
226 case eNumeric_:
227 return UnParseTime_ (count (), p);
228 }
230 return String{};
231 }
232 }
233 template <typename T>
234 inline T Duration::AsPinned () const
235 requires (same_as<T, timeval> or integral<T> or floating_point<T> or same_as<T, Characters::String> or Common::IDuration<T> or
236 Common::ITimePoint<T>)
237 {
238 if constexpr (integral<T> or floating_point<T>) {
239 if (this->count () < numeric_limits<T>::min ()) [[unlikely]] {
240 return numeric_limits<T>::min ();
241 }
242 else if (this->count () > numeric_limits<T>::max ()) [[unlikely]] {
243 return numeric_limits<T>::max ();
244 }
245 return As<T> ();
246 }
247 else if constexpr (same_as<T, timeval>) {
248 if (this->count () > static_cast<rep> (numeric_limits<long>::max ())) [[unlikely]] {
249 return timeval{numeric_limits<long>::max (), 0}; // close enuf for now - if that big, do the nanoseconds matter?
250 }
251 return As<T> ();
252 }
253 else if constexpr (same_as<T, Characters::String>) {
254 return As<T> ();
255 }
256 else if constexpr (Common::IDuration<T>) {
257#if (defined(__clang_major__) && !defined(__APPLE__) && (__clang_major__ >= 10)) || \
258 (defined(__clang_major__) && defined(__APPLE__) && (__clang_major__ >= 12))
259 DISABLE_COMPILER_CLANG_WARNING_START ("clang diagnostic ignored \"-Wimplicit-int-float-conversion\""); // warning: implicit conversion from 'std::__1::chrono::duration<long long, std::__1::ratio<1, 1> >::rep' (aka 'long long') to 'double' changes value from 9223372036854775807 to 9223372036854775808
260#endif
261 /*
262 * To convert, will do( my_ratio::num/my_ratio::den) * (target::den / target::num) .
263 * Question is - will any of that overflow.
264 *
265 * Hard to be sure as it depends a little on how you get there (deterministic, just complex).
266 * But easy approximation is:
267 * do math in floating point, and see if would 'fit' in target rep.
268 */
269 using TRatio = typename T::period;
270 auto targetRes = (static_cast<long double> (this->count ()) * period::num / period::den) * TRatio ::den / TRatio::num;
271 if (targetRes < T::min ().count ()) [[unlikely]] {
272 return T::min ();
273 }
274 if (targetRes > T::max ().count ()) [[unlikely]] {
275 return T::max ();
276 }
277#if (defined(__clang_major__) && !defined(__APPLE__) && (__clang_major__ >= 10)) || \
278 (defined(__clang_major__) && defined(__APPLE__) && (__clang_major__ >= 12))
279 DISABLE_COMPILER_CLANG_WARNING_END ("clang diagnostic ignored \"-Wimplicit-int-float-conversion\"");
280#endif
281 return As<T> ();
282 }
283 else if constexpr (Common::ITimePoint<T>) {
284 return T{this->AsPinned<typename T::duration> ()};
285 }
286 }
287 inline Characters::String Duration::Format (const PrettyPrintInfo& prettyPrintInfo) const
288 {
289 return PrettyPrint (prettyPrintInfo);
290 }
292 {
293 return Format ();
294 }
295 inline constexpr Duration Duration::min ()
296 {
297 return inherited::min ();
298 }
299 inline constexpr Duration Duration::max ()
300 {
301 return inherited::max ();
302 }
303
304 /*
305 ********************************************************************************
306 ******************** Literals::operator "" _duration ***************************
307 ********************************************************************************
308 */
309 inline namespace Literals {
310 [[nodiscard]] inline Duration operator""_duration (const char* str, size_t len)
311 {
312 return Duration{string{str, str + len}};
313 }
314 [[nodiscard]] inline Duration operator""_duration (const wchar_t* str, size_t len)
315 {
316 return Duration{Characters::String{span{str, len}}};
317 }
318 [[nodiscard]] inline Duration operator""_duration (const char8_t* str, size_t len)
319 {
320 return Duration{Characters::String{span{str, len}}};
321 }
322 [[nodiscard]] inline Duration operator""_duration (const char16_t* str, size_t len)
323 {
324 return Duration{Characters::String{span{str, len}}};
325 }
326 [[nodiscard]] inline Duration operator""_duration (const char32_t* str, size_t len)
327 {
328 return Duration{Characters::String{span{str, len}}};
329 }
330 [[nodiscard]] inline Duration operator""_duration (long double _Val) noexcept
331 {
332 return Duration{_Val};
333 }
334 }
335
336 /*
337 ********************************************************************************
338 ***************************** Duration operators *******************************
339 ********************************************************************************
340 */
341 inline Duration operator+ (const DurationSeconds& lhs, const Duration& rhs)
342 {
343 return Duration{lhs + rhs.As<DurationSeconds> ()};
344 }
345 inline Duration operator* (long double lhs, const Duration& rhs)
346 {
347 return Duration{rhs.As<DurationSeconds> () * lhs};
348 }
349
350}
351
353
354 /*
355 ********************************************************************************
356 ****************************** RangeTraits::Default ****************************
357 ********************************************************************************
358 */
359 inline constexpr Time::Duration Default<Time::Duration>::kLowerBound = Time::Duration::min ();
360 inline constexpr Time::Duration Default<Time::Duration>::kUpperBound = Time::Duration::max ();
361 inline Time::Duration Default<Time::Duration>::GetNext (Time::Duration i)
362 {
363 using Time::Duration;
364 return Duration{::nextafter (i.As<Duration::rep> (), numeric_limits<Duration::rep>::max ())};
365 }
366 inline Time::Duration Default<Time::Duration>::GetPrevious (Time::Duration i)
367 {
368 using Time::Duration;
369 return Duration{::nextafter (i.As<Duration::rep> (), numeric_limits<Duration::rep>::min ())};
370 }
371
372}
#define AssertNotReached()
Definition Assertions.h:355
chrono::duration< double > DurationSeconds
chrono::duration<double> - a time span (length of time) measured in seconds, but high precision.
Definition Realtime.h:57
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
Duration is a chrono::duration<double> (=.
Definition Duration.h:96
nonvirtual Characters::String ToString() const
Definition Duration.inl:291
nonvirtual Characters::String Format(const PrettyPrintInfo &prettyPrintInfo=kDefaultPrettyPrintInfo) const
like javascript 'humanize' APIs
Definition Duration.inl:287
nonvirtual u8string AsUTF8() const
Definition Duration.inl:114
nonvirtual Characters::String PrettyPrint(const PrettyPrintInfo &prettyPrintInfo=kDefaultPrettyPrintInfo) const
Definition Duration.cpp:105
static constexpr Duration min()
Definition Duration.inl:295
static constexpr Duration max()
Definition Duration.inl:299