Commit | Line | Data |
---|---|---|
0e23f538 TJ |
1 | /* |
2 | The software in this package is distributed under the GNU General | |
3 | Public License version 2 (with a special exception described below). | |
4 | ||
5 | A copy of GNU General Public License (GPL) is included in this distribution, | |
6 | in the file COPYING.GPL. | |
7 | ||
8 | As a special exception, if other files instantiate templates or use macros | |
9 | or inline functions from this file, or you compile this file and link it | |
10 | with other works to produce a work based on this file, this file | |
11 | does not by itself cause the resulting work to be covered | |
12 | by the GNU General Public License. | |
13 | ||
14 | However the source code for this file must still be made available | |
15 | in accordance with section (3) of the GNU General Public License. | |
16 | ||
17 | This exception does not invalidate any other reasons why a work based | |
18 | on this file might be covered by the GNU General Public License. | |
19 | */ | |
1b5dfd98 TJ |
20 | /** @file |
21 | * @brief time related functions. | |
22 | * | |
23 | * @copyright Copyright © 2001-2008 by Intra2net AG | |
1b5dfd98 | 24 | */ |
e93545dd GE |
25 | |
26 | #ifndef __TIMEFUNC_HXX | |
27 | #define __TIMEFUNC_HXX | |
28 | ||
e36ca33c | 29 | #include <climits> |
8b5814e2 | 30 | #include <errno.h> |
1b5dfd98 | 31 | #include <list> |
e36ca33c | 32 | #include <string> |
1b5dfd98 | 33 | |
8b5814e2 PG |
34 | #include <boost/optional.hpp> |
35 | ||
0c7e72d7 | 36 | #include <week.hpp> |
f1499910 | 37 | |
e36ca33c PG |
38 | #include "stringfunc.hxx" |
39 | ||
40 | #if __cplusplus >= 201103 | |
41 | # define CONSTEXPR constexpr | |
42 | # define NOEXCEPT noexcept | |
43 | #else | |
44 | # define CONSTEXPR | |
45 | # define NOEXCEPT | |
46 | #endif | |
47 | ||
48 | #define TIME_CONST_FACTOR_NANO (1000L * 1000 * 1000) | |
49 | ||
e93545dd GE |
50 | double prec_time(void); |
51 | ||
dad9e26f | 52 | time_t date_to_seconds(const std::string &date); |
e93545dd GE |
53 | |
54 | std::string make_nice_time(int seconds); | |
7839bd53 | 55 | std::string format_full_time(time_t seconds); |
25f3d405 | 56 | std::string format_date(time_t seconds); |
87869870 | 57 | void seconds_to_hour_minute(int seconds, int *hour, int *minute); |
c0368918 GE |
58 | void split_daysec(int daysec, int *outhours=NULL, int *outminutes=NULL, int *outseconds=NULL); |
59 | std::string output_hour_minute(int hour, int minute, bool h_for_00=true, int seconds=0); | |
2c66f490 GE |
60 | |
61 | inline std::string output_hour_minute_from_seconds(int seconds) | |
62 | { | |
63 | int hour, minute; | |
c0368918 | 64 | split_daysec(seconds,&hour,&minute); |
2c66f490 GE |
65 | return output_hour_minute(hour,minute); |
66 | } | |
e93545dd | 67 | |
4e157d1d TJ |
68 | std::string get_month_name(unsigned char month); |
69 | ||
1b5dfd98 TJ |
70 | /** |
71 | * @brief structure representing a single (half-open) interval. | |
72 | */ | |
73 | class Interval | |
74 | { | |
75 | public: | |
76 | Interval() | |
77 | : m_lower_bound(0) | |
78 | , m_upper_bound(0) | |
80f30818 TJ |
79 | , m_weak_mark(0) |
80 | , m_changed(false) | |
1b5dfd98 TJ |
81 | { |
82 | } // | |
83 | ||
80f30818 | 84 | Interval( unsigned int start, unsigned int end, int weak_mark= 0 ) |
1b5dfd98 TJ |
85 | : m_lower_bound(start) |
86 | , m_upper_bound(end) | |
80f30818 TJ |
87 | , m_weak_mark(weak_mark) |
88 | , m_changed(false) | |
1b5dfd98 TJ |
89 | { |
90 | } // | |
91 | ||
d181c3bc TJ |
92 | |
93 | void clear(); | |
94 | ||
1b5dfd98 TJ |
95 | bool is_valid() const |
96 | { | |
97 | return m_lower_bound <= m_upper_bound; | |
98 | } // eo is_valid() const | |
99 | ||
100 | bool empty() const | |
101 | { | |
102 | return m_lower_bound == m_upper_bound; | |
103 | } // eo empty() const | |
104 | ||
105 | ||
106 | unsigned int lower_bound() const { return m_lower_bound; } | |
107 | unsigned int upper_bound() const { return m_upper_bound; } | |
108 | ||
80f30818 TJ |
109 | int weak_mark() const { return m_weak_mark; } |
110 | ||
111 | bool changed() const { return m_changed; } | |
112 | ||
1b5dfd98 TJ |
113 | |
114 | bool operator== (const Interval& other) const | |
115 | { | |
116 | return m_lower_bound == other.m_lower_bound and m_upper_bound == other.m_upper_bound; | |
117 | } // eo operator==(const Interval&) | |
118 | ||
119 | ||
ebc3b584 TJ |
120 | bool operator!=(const Interval& other) const |
121 | { | |
122 | return not (*this == other); | |
123 | } // eo operator!=(const Interval&) | |
124 | ||
125 | ||
1b5dfd98 TJ |
126 | /** |
127 | * @brief less operator. compares only the start times! | |
128 | * @param other the other interval to compare with. | |
129 | * @return @a true if the current start is less than the other start. | |
130 | */ | |
131 | bool operator<(const Interval& other) const | |
132 | { | |
133 | return m_lower_bound < other.m_lower_bound; | |
134 | } // eo operator<(const Interval&) | |
135 | ||
136 | ||
137 | bool intersects(const Interval& other) const; | |
138 | bool contains(const Interval& other) const; | |
139 | ||
140 | ||
141 | protected: | |
142 | ||
143 | friend class Intervals; | |
144 | ||
145 | unsigned int m_lower_bound; | |
146 | unsigned int m_upper_bound; | |
147 | ||
80f30818 TJ |
148 | int m_weak_mark; |
149 | bool m_changed; | |
150 | ||
1b5dfd98 TJ |
151 | }; // eo Interval |
152 | ||
153 | ||
154 | ||
155 | /** | |
156 | * @brief structure representing a combination of single disjoint (half open) intervals. | |
157 | * | |
158 | * Basic idea is that this structure provides an interface for adding and | |
159 | * subtracting single intervals and keeps the internal list of intervals as | |
160 | * a list of disjoint intervals. | |
161 | * | |
162 | * @note the list is sorted by the start; lower comes first. | |
163 | * | |
164 | * @note the class provides some methods similar to STL container classes; | |
165 | * i.e. it can be used with (at least some) STL algorithms. | |
166 | * | |
167 | * @internal | |
168 | * we use a std::list for the intervals; this means we don't invalidate all | |
169 | * iterators when we insert or delete within loops... | |
170 | * And we use that fact!! | |
171 | */ | |
172 | class Intervals | |
173 | { | |
174 | public: | |
175 | typedef std::list< Interval > IntervalList; | |
176 | typedef IntervalList::value_type value_type; | |
177 | typedef IntervalList::const_iterator const_iterator; | |
178 | typedef IntervalList::const_iterator iterator; // we allow only const... | |
179 | typedef IntervalList::size_type size_type; | |
180 | ||
181 | public: | |
182 | Intervals(); | |
183 | ||
184 | void add(const Interval& new_frame); | |
185 | void sub(const Interval& new_frame); | |
186 | ||
d181c3bc | 187 | void clear(); |
1b5dfd98 TJ |
188 | |
189 | const_iterator begin() const { return m_intervals.begin(); } | |
190 | const_iterator end() const { return m_intervals.end(); } | |
191 | ||
192 | bool empty() const { return m_intervals.empty(); } | |
193 | const Interval& front() const { return m_intervals.front(); } | |
194 | const Interval& back() const { return m_intervals.back(); } | |
195 | ||
196 | size_type size() const { return m_intervals.size(); } | |
197 | ||
198 | bool intersects(const Interval& other) const; | |
199 | bool intersects(const Intervals& other) const; | |
200 | ||
201 | bool contains(const Interval& other) const; | |
202 | bool contains(const Intervals& other) const; | |
203 | ||
e156de7c TJ |
204 | bool contains_exact(const Interval& other) const; |
205 | ||
1b5dfd98 | 206 | bool operator==(const Intervals& other) const; |
ebc3b584 | 207 | bool operator!=(const Intervals& other) const { return not (*this == other) ; } |
1b5dfd98 TJ |
208 | |
209 | Intervals& operator+=(const Interval& other); | |
210 | Intervals& operator-=(const Interval& other); | |
211 | ||
212 | Intervals& operator+=(const Intervals& other); | |
213 | Intervals& operator-=(const Intervals& other); | |
214 | ||
215 | protected: | |
216 | ||
217 | std::list< Interval > m_intervals; | |
218 | ||
219 | }; // eo Intervals | |
220 | ||
221 | ||
96d0be2e TJ |
222 | /* |
223 | ** clock funcs: | |
224 | */ | |
225 | ||
226 | ||
227 | bool monotonic_clock_gettime(long int& seconds, long int& nano_seconds); | |
b7e17426 | 228 | long long monotonic_clock_gettime_nano(); |
96d0be2e TJ |
229 | |
230 | bool realtime_clock_gettime(long int& seconds, long int& nano_seconds); | |
231 | ||
8b5814e2 PG |
232 | namespace I2n { |
233 | ||
234 | namespace clock { | |
235 | ||
e36ca33c PG |
236 | namespace { |
237 | ||
238 | /* helper for ctor initializer list; we still lack aggregate initializers */ | |
239 | struct timespec | |
240 | timespec_of_parts (const time_t sec, const long nsec) | |
241 | { | |
242 | struct timespec ret = { sec, nsec}; | |
243 | ||
244 | return ret; | |
245 | } | |
246 | ||
247 | } /* [namespace] */ | |
248 | ||
8b5814e2 PG |
249 | namespace type { |
250 | /* | |
251 | * represent the clock id options from clock_gettime(2) as | |
252 | * a pair of enums. by default, CLOCK_MONOTONIC_COARSE is used | |
253 | * everywhere since that’s what we want in most cases. | |
254 | */ | |
255 | enum id { | |
256 | mono, /* CLOCK_MONOTONIC_COARSE */ | |
257 | real, /* CLOCK_REALIME_COARSE */ | |
258 | boot, /* CLOCK_BOOTTIME */ | |
259 | cpu, /* CLOCK_CPUTIME_* */ | |
260 | }; | |
261 | ||
262 | /* | |
263 | * for clocks that support it: non-coarse or raw variants; if a variant | |
264 | * does not apply to a given clock, it is ignored | |
265 | */ | |
266 | enum variant { | |
267 | dflt, /* all */ | |
268 | exact, /* mono, real: not (*_COARSE) */ | |
269 | raw, /* mono: _RAW */ | |
270 | process, /* cpu: *_PROCESS_* */ | |
271 | thread, /* cpu: *_THREAD_* */ | |
272 | }; | |
273 | ||
274 | } /* [namespace type] */ | |
275 | ||
276 | ||
277 | class Time { | |
278 | ||
279 | private: | |
e36ca33c | 280 | struct timespec value; |
8b5814e2 PG |
281 | |
282 | public: | |
e36ca33c PG |
283 | enum type::id id; |
284 | enum type::variant variant; | |
285 | int err; | |
286 | ||
287 | private: | |
288 | /* | |
289 | * Handle decimal part (nanosecond) overflow; this is performed | |
290 | * after arithmetic operations and whenever we there is the | |
291 | * possibility of unsanitized input for example in constructors | |
292 | * from other types and suchlike. | |
293 | * | |
294 | * POSIX defines the ns part as *long*. Technically, that means | |
295 | * that on machines where *sizeof long* equals *sizeof int*, it can | |
296 | * represent only up to arund 2.1 seconds. In this range, the loop | |
297 | * version is most likely faster than division. However, since in | |
298 | * practice *long* is 8 bytes just about anywhere, we have to | |
299 | * handle greater dividends first. | |
300 | */ | |
301 | inline void | |
302 | carry_nsec (void) | |
303 | { | |
304 | # if LONG_BIT > 32 | |
305 | if ( this->value.tv_nsec < -3L * TIME_CONST_FACTOR_NANO | |
306 | || this->value.tv_nsec > 3L * TIME_CONST_FACTOR_NANO) | |
307 | { | |
308 | const long sec = this->value.tv_nsec / TIME_CONST_FACTOR_NANO; | |
309 | this->value.tv_nsec -= sec * TIME_CONST_FACTOR_NANO; | |
310 | this->value.tv_sec += sec; | |
311 | } | |
312 | # endif /* [LONG_BIT > 32] */ | |
313 | while (this->value.tv_nsec >= TIME_CONST_FACTOR_NANO) { | |
314 | this->value.tv_sec += 1; | |
315 | this->value.tv_nsec -= TIME_CONST_FACTOR_NANO; | |
316 | } | |
317 | ||
318 | while (this->value.tv_nsec < 0) { | |
319 | this->value.tv_sec -= 1; | |
320 | this->value.tv_nsec += TIME_CONST_FACTOR_NANO; | |
321 | } | |
322 | } | |
8b5814e2 PG |
323 | |
324 | /* ctors *************************************************************/ | |
325 | public: | |
326 | ||
327 | Time (const enum type::id id = type::mono, | |
e36ca33c PG |
328 | const enum type::variant var = type::dflt) NOEXCEPT; |
329 | ||
330 | inline Time (const Time &t) NOEXCEPT | |
331 | : value (t.value) | |
332 | , id (t.id) | |
333 | , variant (t.variant) | |
334 | , err (t.err) | |
335 | { } | |
336 | ||
337 | inline Time (const time_t sec, | |
338 | const long nsec = 0, | |
339 | const enum type::id id = type::mono, | |
340 | const enum type::variant var = type::dflt, | |
341 | const int err = 0) NOEXCEPT | |
342 | : value (timespec_of_parts (sec, nsec)) | |
343 | , id (id) | |
344 | , variant (var) | |
345 | , err (err) | |
346 | { this->carry_nsec (); } | |
347 | ||
348 | /* value read access *************************************************/ | |
8b5814e2 PG |
349 | public: |
350 | ||
e36ca33c | 351 | inline CONSTEXPR const struct timespec &get_time (void) const NOEXCEPT |
8b5814e2 PG |
352 | { return this->value; } |
353 | ||
e36ca33c PG |
354 | inline CONSTEXPR const time_t &get_sec (void) const NOEXCEPT |
355 | { return this->value.tv_sec; } | |
8b5814e2 | 356 | |
e36ca33c | 357 | inline CONSTEXPR const long &get_nsec (void) const NOEXCEPT |
8b5814e2 PG |
358 | { return this->value.tv_nsec; } |
359 | ||
e36ca33c | 360 | int64_t as_nanosec (void) const NOEXCEPT; |
8b5814e2 | 361 | |
e36ca33c | 362 | long as_nanosec_L (void) const NOEXCEPT; |
8b5814e2 | 363 | |
e36ca33c | 364 | /* value write access ************************************************/ |
8b5814e2 PG |
365 | public: |
366 | ||
367 | inline void | |
e36ca33c PG |
368 | swap (Time &t) NOEXCEPT |
369 | { | |
370 | std::swap (this->value , t.value ); | |
371 | std::swap (this->id , t.id ); | |
372 | std::swap (this->variant, t.variant); | |
373 | std::swap (this->err , t.err ); | |
374 | } | |
375 | ||
376 | Time &operator= (Time t) NOEXCEPT; | |
377 | ||
378 | Time &operator= (struct timespec ts) NOEXCEPT; | |
8b5814e2 PG |
379 | |
380 | inline void | |
e36ca33c PG |
381 | set (const struct timespec &ts) NOEXCEPT |
382 | { | |
383 | this->value = ts; | |
384 | this->carry_nsec (); | |
385 | } | |
386 | ||
387 | inline void | |
388 | set (const time_t sec, | |
389 | const long nsec, | |
390 | const enum type::id id = type::mono, | |
391 | const enum type::variant var = type::dflt) NOEXCEPT | |
8b5814e2 PG |
392 | { |
393 | this->value.tv_sec = sec; | |
394 | this->value.tv_nsec = nsec; | |
e36ca33c PG |
395 | this->id = id; |
396 | this->variant = var; | |
397 | ||
398 | this->carry_nsec (); | |
399 | } | |
8b5814e2 | 400 | |
e36ca33c PG |
401 | bool set (void) NOEXCEPT; |
402 | ||
403 | void unset (void) NOEXCEPT; | |
404 | ||
405 | /* arithmetic ********************************************************/ | |
406 | public: | |
8b5814e2 | 407 | |
e36ca33c PG |
408 | Time &add (const time_t sec, const long nsec) NOEXCEPT; |
409 | ||
410 | Time &subtract (const time_t sec, const long nsec) NOEXCEPT; | |
411 | ||
412 | inline Time &add (const Time &t2) NOEXCEPT | |
413 | { return this->add (t2.value.tv_sec, t2.value.tv_nsec); } | |
414 | ||
415 | inline Time &add (const time_t t2) NOEXCEPT | |
416 | { return this->add (t2, 0L); }; | |
417 | ||
418 | inline Time &subtract (const Time &t2) NOEXCEPT | |
419 | { return this->subtract (t2.value.tv_sec, t2.value.tv_nsec); } | |
420 | ||
421 | inline Time &subtract (const time_t t2) NOEXCEPT | |
422 | { return this->subtract (t2, 0L); }; | |
423 | ||
424 | Time &scale (const time_t factor) NOEXCEPT; | |
425 | ||
426 | friend int compare (const Time &t1, const Time &t2) NOEXCEPT; | |
427 | ||
428 | inline Time | |
429 | difference (const Time &t) NOEXCEPT | |
430 | { return (*this < t) ? t - *this : *this - t; } | |
431 | ||
432 | /* overloads *********************************************************/ | |
433 | public: | |
434 | ||
435 | inline Time | |
436 | operator+ (const Time &t2) const NOEXCEPT | |
437 | { return Time (*this).add (t2); } | |
438 | ||
439 | inline Time | |
440 | operator+ (const time_t t2) const NOEXCEPT | |
441 | { return Time (*this).add (t2); } | |
442 | ||
443 | inline Time & | |
444 | operator+= (const Time &t2) NOEXCEPT | |
445 | { return this->add (t2); } | |
446 | ||
447 | inline Time & | |
448 | operator+= (const time_t t2) NOEXCEPT | |
449 | { return this->add (t2); } | |
450 | ||
451 | inline Time | |
452 | operator- (const Time &t2) const NOEXCEPT | |
453 | { return Time (*this).subtract (t2); } | |
454 | ||
455 | inline Time | |
456 | operator- (const time_t t2) const NOEXCEPT | |
457 | { return Time (*this).subtract (t2); } | |
458 | ||
459 | inline Time & | |
460 | operator-= (const Time &t2) NOEXCEPT | |
461 | { return this->subtract (t2); } | |
462 | ||
463 | inline Time & | |
464 | operator-= (const time_t t2) NOEXCEPT | |
465 | { return this->subtract (t2); } | |
466 | ||
467 | inline Time | |
468 | operator* (const time_t factor) const NOEXCEPT | |
469 | { return Time (*this).scale (factor); } | |
470 | ||
471 | inline Time & | |
472 | operator*= (const time_t factor) NOEXCEPT | |
473 | { return this->scale (factor); } | |
474 | ||
475 | friend CONSTEXPR bool | |
476 | operator== (const Time &t1, const Time &t2) NOEXCEPT; | |
477 | ||
478 | friend CONSTEXPR bool | |
479 | operator< (const Time &t1, const Time &t2) NOEXCEPT; | |
480 | ||
481 | friend CONSTEXPR bool | |
482 | operator> (const Time &t1, const Time &t2) NOEXCEPT; | |
483 | ||
484 | friend std::ostream & | |
485 | operator<< (std::ostream &os, const Time &t); | |
8b5814e2 PG |
486 | |
487 | }; /* [class Time] */ | |
488 | ||
e36ca33c PG |
489 | inline Time |
490 | operator+ (const time_t t1, const Time &t2) NOEXCEPT | |
491 | { return Time (t1) + t2; } | |
492 | ||
493 | inline Time | |
494 | operator- (const time_t t1, const Time &t2) NOEXCEPT | |
495 | { return Time (t1) - t2; } | |
496 | ||
497 | int compare (const Time &t1, const Time &t2) NOEXCEPT; | |
498 | ||
499 | /* | |
500 | * comparison for equality also considers the clock type; | |
501 | */ | |
502 | inline CONSTEXPR bool | |
503 | operator== (const Time &t1, const Time &t2) NOEXCEPT | |
504 | { | |
505 | return t1.id == t2.id && t1.variant == t2.variant | |
506 | && t1.value.tv_sec == t2.value.tv_sec | |
507 | && t1.value.tv_nsec == t2.value.tv_nsec | |
508 | ; | |
509 | } | |
510 | ||
511 | /* these ignore the *id* and *variant* fields */ | |
512 | inline CONSTEXPR bool | |
513 | operator< (const Time &t1, const Time &t2) NOEXCEPT | |
514 | { | |
515 | return t1.value.tv_sec < t2.value.tv_sec | |
516 | || ( t1.value.tv_sec == t2.value.tv_sec | |
517 | && t1.value.tv_nsec < t2.value.tv_nsec) | |
518 | ; | |
519 | } | |
520 | ||
521 | /* these ignore the *id* and *variant* fields */ | |
522 | inline CONSTEXPR bool | |
523 | operator> (const Time &t1, const Time &t2) NOEXCEPT | |
524 | { | |
525 | return t1.value.tv_sec > t2.value.tv_sec | |
526 | || ( t1.value.tv_sec == t2.value.tv_sec | |
527 | && t1.value.tv_nsec > t2.value.tv_nsec) | |
528 | ; | |
529 | } | |
530 | ||
531 | inline std::ostream & | |
532 | operator<< (std::ostream &os, const Time &t) | |
533 | { | |
534 | os << I2n::to_string (t.value.tv_sec) << "ms, " | |
535 | << I2n::to_string (t.value.tv_nsec) << "ns" | |
536 | ; | |
537 | ||
538 | return os; | |
539 | } | |
540 | ||
8b5814e2 PG |
541 | boost::optional<Time> |
542 | now (const enum type::id id = type::mono, | |
e36ca33c PG |
543 | const enum type::variant var = type::dflt) NOEXCEPT; |
544 | ||
545 | Time | |
546 | zero (const enum type::id id = type::mono, | |
547 | const enum type::variant var = type::dflt) NOEXCEPT; | |
8b5814e2 PG |
548 | |
549 | } /* [namespace clock] */ | |
550 | ||
551 | } /* [namespace I2n] */ | |
1b5dfd98 TJ |
552 | |
553 | ||
e93545dd | 554 | #endif |