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