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