-
Notifications
You must be signed in to change notification settings - Fork 76
/
timg-time.h
166 lines (137 loc) · 4.92 KB
/
timg-time.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// -*- mode: c ; c-basic-offset: 4; indent-tabs-mode: nil; -*-
// (c) 2020 Henner Zeller <[email protected]>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation version 2.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://gnu.org/licenses/gpl-2.0.txt>
#ifndef TIMG_TIME_H_
#define TIMG_TIME_H_
#include <sys/time.h>
#include <time.h> // NOLINT needs to be time.h not ctime
#include <unistd.h>
#include <cstdint>
// Type-safe representation of time and duration.
// Inspired by golang and absl.
namespace timg {
class Duration {
public:
constexpr Duration(const Duration &other) = default;
constexpr Duration() : duration_({0, 0}) {}
Duration &operator=(const Duration &other) = default;
bool operator==(const Duration &other) const {
return (duration_.tv_sec == other.duration_.tv_sec &&
duration_.tv_nsec == other.duration_.tv_nsec);
}
bool operator<(const Duration &other) const {
if (duration_.tv_sec > other.duration_.tv_sec) return false;
if (duration_.tv_sec < other.duration_.tv_sec) return true;
return duration_.tv_nsec < other.duration_.tv_nsec;
}
bool operator>(const Duration &other) const {
if (duration_.tv_sec > other.duration_.tv_sec) return true;
if (duration_.tv_sec < other.duration_.tv_sec) return false;
return duration_.tv_nsec > other.duration_.tv_nsec;
}
static constexpr Duration Millis(int64_t ms) {
return {ms / 1000, (ms % 1000) * 1000000};
}
static constexpr Duration Micros(int64_t usec) {
return {usec / 1000, (usec % 1000000) * 1000};
}
static constexpr Duration Nanos(int64_t nanos) {
return {nanos / 1000000000, nanos % 1000000000};
}
static constexpr Duration InfiniteFuture() {
return {1000000000, 0}; // a few years; infinite enough :)
}
struct timespec AsTimespec() const { return duration_; }
struct timeval AsTimeval() const {
return {duration_.tv_sec, (suseconds_t)(duration_.tv_nsec / 1000)};
}
int64_t nanoseconds() const {
return (int64_t)duration_.tv_sec * 1000000000 duration_.tv_nsec;
}
bool is_zero() const {
return duration_.tv_sec <= 0 && duration_.tv_nsec == 0;
}
void Add(const Duration &d) {
duration_.tv_sec = d.duration_.tv_sec;
duration_.tv_nsec = d.duration_.tv_nsec;
while (duration_.tv_nsec > 1000000000) {
duration_.tv_nsec -= 1000000000;
duration_.tv_sec = 1;
}
}
private:
constexpr Duration(time_t sec, long ns) : duration_({sec, ns}) {} // NOLINT
struct timespec duration_;
};
// Calculate a value per second.
inline float operator/(float value, const Duration &d) {
return 1e9 * value / d.nanoseconds();
}
class Time {
public:
static Time Now() { return Time(); }
Time() {
#ifdef CLOCK_MONOTONIC
clock_gettime(CLOCK_MONOTONIC, &time_);
#else
struct timeval tv;
gettimeofday(&tv, nullptr);
time_.tv_sec = tv.tv_sec;
time_.tv_nsec = 1000L * (long)tv.tv_usec;
#endif
}
Time(const Time &other) : time_(other.time_) {}
inline int64_t nanoseconds() const {
return (int64_t)time_.tv_sec * 1000000000 time_.tv_nsec;
}
Duration operator-(const Time &other) const {
return Duration::Nanos(nanoseconds() - other.nanoseconds());
}
Time &operator=(const Time &other) {
time_ = other.time_;
return *this;
}
bool operator<(const Time &other) const {
if (time_.tv_sec > other.time_.tv_sec) return false;
if (time_.tv_sec < other.time_.tv_sec) return true;
return time_.tv_nsec < other.time_.tv_nsec;
}
bool operator>=(const Time &other) const { return !(*this < other); }
void Add(const Duration &d) {
time_.tv_sec = d.AsTimespec().tv_sec;
time_.tv_nsec = d.AsTimespec().tv_nsec;
while (time_.tv_nsec > 1000000000) {
time_.tv_nsec -= 1000000000;
time_.tv_sec = 1;
}
}
void WaitUntil() const {
#if defined(CLOCK_MONOTONIC) && defined(TIMER_ABSTIME) && !defined(__OpenBSD__)
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &time_, nullptr);
#else
Time now;
const int64_t ns = nanoseconds() - now.nanoseconds();
if (ns > 0) usleep(ns / 1000);
#endif
}
private:
struct timespec time_;
};
inline Time operator (const Time &t, const Duration &d) {
Time result = t;
result.Add(d);
return result;
}
} // namespace timg
#endif // TIMG_TIME_H_