libpromeki 1.0.0-alpha
PROfessional MEdia toolKIt
 
Loading...
Searching...
No Matches
timestamp.h
Go to the documentation of this file.
1
8#pragma once
9
10
11#include <promeki/config.h>
12#if PROMEKI_ENABLE_CORE
13#include <chrono>
14#include <cstdint>
15#include <thread>
16#include <promeki/namespace.h>
17#include <promeki/string.h>
18#include <promeki/duration.h>
19#include <promeki/datatype.h>
20#include <promeki/result.h>
21
22PROMEKI_NAMESPACE_BEGIN
23
24class DataStream;
25
48class TimeStamp {
49 public:
50 PROMEKI_DATATYPE(TimeStamp, DataTypeTimeStamp, 1)
51
52
59 static constexpr int64_t Invalid = INT64_MIN;
60
62 Error writeToStream(DataStream &s) const;
64 template <uint32_t V> static Result<TimeStamp> readFromStream(DataStream &s);
65
67 using Clock = std::chrono::steady_clock;
69 using Value = std::chrono::time_point<Clock>;
71 using Duration = Clock::duration;
72
78 static Duration secondsToDuration(double val) {
79 std::chrono::duration<double> doubleDuration(val);
80 return std::chrono::duration_cast<Duration>(doubleDuration);
81 }
82
87 static void sleep(const Duration &d) {
88 std::this_thread::sleep_for(d);
89 return;
90 }
91
96 static TimeStamp now() {
97 return TimeStamp(
98 std::chrono::duration_cast<std::chrono::nanoseconds>(Clock::now().time_since_epoch())
99 .count());
100 }
101
103 TimeStamp() = default;
104
114 explicit TimeStamp(int64_t ns) : _ns(ns) {}
115
120 TimeStamp(const Value &v)
121 : _ns(std::chrono::duration_cast<std::chrono::nanoseconds>(v.time_since_epoch()).count()) {}
122
124 bool isValid() const { return _ns != Invalid; }
125
135 operator Value() const { return Value(std::chrono::nanoseconds(_ns)); }
136
146 TimeStamp &operator+=(const Duration &duration) {
147 if (isValid()) {
148 _ns += std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count();
149 }
150 return *this;
151 }
152
162 TimeStamp &operator-=(const Duration &duration) {
163 if (isValid()) {
164 _ns -= std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count();
165 }
166 return *this;
167 }
168
173 void setValue(const Value &v) {
174 _ns = std::chrono::duration_cast<std::chrono::nanoseconds>(v.time_since_epoch()).count();
175 return;
176 }
177
188 Value value() const { return Value(std::chrono::nanoseconds(_ns)); }
189
197 void invalidate() { _ns = Invalid; }
198
200 void update() {
201 _ns = std::chrono::duration_cast<std::chrono::nanoseconds>(Clock::now().time_since_epoch())
202 .count();
203 }
204
210 void sleepUntil() const {
211 if (isValid()) std::this_thread::sleep_until(value());
212 }
213
218 Duration timeSinceEpoch() const {
219 return std::chrono::duration_cast<Duration>(std::chrono::nanoseconds(_ns));
220 }
221
229 double seconds() const {
230 if (!isValid()) return 0.0;
231 return static_cast<double>(_ns) / 1'000'000'000.0;
232 }
233
241 int64_t milliseconds() const {
242 if (!isValid()) return 0;
243 return _ns / 1'000'000LL;
244 }
245
253 int64_t microseconds() const {
254 if (!isValid()) return 0;
255 return _ns / 1'000LL;
256 }
257
267 int64_t nanoseconds() const { return _ns; }
268
276 double elapsedSeconds() const {
277 if (!isValid()) return 0.0;
278 return std::chrono::duration_cast<std::chrono::duration<double>>(Clock::now() - value()).count();
279 }
280
288 int64_t elapsedMilliseconds() const {
289 if (!isValid()) return 0;
290 return std::chrono::duration_cast<std::chrono::milliseconds>(Clock::now() - value()).count();
291 }
292
300 int64_t elapsedMicroseconds() const {
301 if (!isValid()) return 0;
302 return std::chrono::duration_cast<std::chrono::microseconds>(Clock::now() - value()).count();
303 }
304
312 int64_t elapsedNanoseconds() const {
313 if (!isValid()) return 0;
314 return std::chrono::duration_cast<std::chrono::nanoseconds>(Clock::now() - value()).count();
315 }
316
324 String toString() const {
325 if (!isValid()) return String("invalid");
326 return String::number(seconds());
327 }
328
337 static Result<TimeStamp> fromString(const String &s) {
338 if (s == "invalid") return makeResult(TimeStamp());
339 Error e;
340 double v = s.to<double>(&e);
341 if (e.isError()) return makeError<TimeStamp>(Error::ParseFailed);
342 return makeResult(TimeStamp(Value(secondsToDuration(v))));
343 }
344
346 bool operator==(const TimeStamp &other) const { return _ns == other._ns; }
347
349 bool operator!=(const TimeStamp &other) const { return _ns != other._ns; }
350
352 bool operator<(const TimeStamp &other) const { return _ns < other._ns; }
354 bool operator>(const TimeStamp &other) const { return _ns > other._ns; }
356 bool operator<=(const TimeStamp &other) const { return _ns <= other._ns; }
358 bool operator>=(const TimeStamp &other) const { return _ns >= other._ns; }
359
361 operator String() const { return toString(); }
362
363 private:
364 int64_t _ns = Invalid;
365};
366
376inline TimeStamp operator+(const TimeStamp &ts, const TimeStamp::Duration &duration) {
377 TimeStamp result(ts);
378 result += duration;
379 return result;
380}
381
391inline TimeStamp operator-(const TimeStamp &ts, const TimeStamp::Duration &duration) {
392 TimeStamp result(ts);
393 result -= duration;
394 return result;
395}
396
397// ---------------------------------------------------------------------------
398// promeki::Duration interop
399//
400// promeki::Duration and TimeStamp::Duration are intentionally different
401// types — promeki::Duration is the library's portable nanosecond-precision
402// value object, while TimeStamp::Duration is the platform's
403// std::chrono::steady_clock::duration. These free function overloads let
404// callers do TimeStamp + promeki::Duration arithmetic directly, without
405// the lossy round-trip through @c secondsToDuration / @c toSecondsDouble
406// that earlier code had to fall back on.
407//
408// Implemented as free functions so the parameter type can be the
409// namespace-level @c promeki::Duration without colliding with the
410// in-class @c TimeStamp::Duration typedef.
411// ---------------------------------------------------------------------------
412
422inline TimeStamp::Duration toClockDuration(const Duration &d) {
423 return std::chrono::duration_cast<TimeStamp::Duration>(std::chrono::nanoseconds(d.nanoseconds()));
424}
425
435inline TimeStamp &operator+=(TimeStamp &ts, const Duration &d) {
436 if (!ts.isValid() || !d.isValid()) {
437 ts.invalidate();
438 } else {
439 ts = TimeStamp(ts.nanoseconds() + d.nanoseconds());
440 }
441 return ts;
442}
443
453inline TimeStamp &operator-=(TimeStamp &ts, const Duration &d) {
454 if (!ts.isValid() || !d.isValid()) {
455 ts.invalidate();
456 } else {
457 ts = TimeStamp(ts.nanoseconds() - d.nanoseconds());
458 }
459 return ts;
460}
461
471inline TimeStamp operator+(const TimeStamp &ts, const Duration &d) {
472 TimeStamp result(ts);
473 result += d;
474 return result;
475}
476
486inline TimeStamp operator-(const TimeStamp &ts, const Duration &d) {
487 TimeStamp result(ts);
488 result -= d;
489 return result;
490}
491
506inline Duration operator-(const TimeStamp &a, const TimeStamp &b) {
507 if (!a.isValid() || !b.isValid()) return Duration();
508 return Duration::fromNanoseconds(a.nanoseconds() - b.nanoseconds());
509}
510
511PROMEKI_NAMESPACE_END
512
513PROMEKI_FORMAT_VIA_TOSTRING(promeki::TimeStamp);
514
515#endif // PROMEKI_ENABLE_CORE