implement basic operations over class Time
[libi2ncommon] / src / timefunc.hxx
CommitLineData
0e23f538
TJ
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on 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
50double prec_time(void);
51
dad9e26f 52time_t date_to_seconds(const std::string &date);
e93545dd
GE
53
54std::string make_nice_time(int seconds);
7839bd53 55std::string format_full_time(time_t seconds);
25f3d405 56std::string format_date(time_t seconds);
87869870 57void seconds_to_hour_minute(int seconds, int *hour, int *minute);
c0368918
GE
58void split_daysec(int daysec, int *outhours=NULL, int *outminutes=NULL, int *outseconds=NULL);
59std::string output_hour_minute(int hour, int minute, bool h_for_00=true, int seconds=0);
2c66f490
GE
60
61inline 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
68std::string get_month_name(unsigned char month);
69
1b5dfd98
TJ
70/**
71 * @brief structure representing a single (half-open) interval.
72 */
73class 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 */
172class 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
227bool monotonic_clock_gettime(long int& seconds, long int& nano_seconds);
b7e17426 228long long monotonic_clock_gettime_nano();
96d0be2e
TJ
229
230bool realtime_clock_gettime(long int& seconds, long int& nano_seconds);
231
8b5814e2
PG
232namespace I2n {
233
234namespace 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