libpromeki 1.0.0-alpha
PROfessional MEdia toolKIt
 
Loading...
Searching...
No Matches
duration.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 <type_traits>
16#include <promeki/namespace.h>
17#include <promeki/string.h>
18#include <promeki/rational.h>
19#include <promeki/datatype.h>
20
21PROMEKI_NAMESPACE_BEGIN
22
23class Error;
24class String;
25class DataStream;
26
41class Duration {
42 public:
43 PROMEKI_DATATYPE(Duration, DataTypeDuration, 1)
44
45
51 static constexpr int64_t Invalid = INT64_MIN;
52
54 Error writeToStream(DataStream &s) const;
56 template <uint32_t V> static Result<Duration> readFromStream(DataStream &s);
57
64 static Duration zero() { return Duration(int64_t{0}); }
65
71 static Duration fromHours(int64_t h) {
72 return Duration(h * 3'600'000'000'000LL);
73 }
74
80 static Duration fromMinutes(int64_t m) {
81 return Duration(m * 60'000'000'000LL);
82 }
83
89 static Duration fromSeconds(int64_t s) {
90 return Duration(s * 1'000'000'000LL);
91 }
92
98 static Duration fromMilliseconds(int64_t ms) {
99 return Duration(ms * 1'000'000LL);
100 }
101
107 static Duration fromMicroseconds(int64_t us) {
108 return Duration(us * 1'000LL);
109 }
110
116 static Duration fromNanoseconds(int64_t ns) { return Duration(ns); }
117
125 template <typename Int, std::enable_if_t<std::is_integral_v<Int>, int> = 0>
126 static Duration fromSamples(int64_t count, Int rate) {
127 if (rate == 0) return zero();
128 return fromNanoseconds(count * 1'000'000'000LL / static_cast<int64_t>(rate));
129 }
130
138 template <typename Float, std::enable_if_t<std::is_floating_point_v<Float>, int> = 0>
139 static Duration fromSamples(int64_t count, Float rate) {
140 if (!(rate > Float(0))) return zero();
141 const double ns = static_cast<double>(count) * 1'000'000'000.0 / static_cast<double>(rate);
142 return fromNanoseconds(static_cast<int64_t>(ns));
143 }
144
154 template <typename T> static Duration fromSamples(int64_t count, const Rational<T> &rate) {
155 if (!rate.isValid() || rate.numerator() == 0) {
156 return zero();
157 }
158 const int64_t num = static_cast<int64_t>(rate.numerator());
159 const int64_t den = static_cast<int64_t>(rate.denominator());
160 return fromNanoseconds(count * den * 1'000'000'000LL / num);
161 }
162
164 Duration() = default;
165
167 bool isValid() const { return _ns != Invalid; }
168
176 int64_t hours() const { return isValid() ? _ns / 3'600'000'000'000LL : 0; }
177
185 int64_t minutes() const { return isValid() ? _ns / 60'000'000'000LL : 0; }
186
194 int64_t seconds() const { return isValid() ? _ns / 1'000'000'000LL : 0; }
195
203 int64_t milliseconds() const { return isValid() ? _ns / 1'000'000LL : 0; }
204
212 int64_t microseconds() const { return isValid() ? _ns / 1'000LL : 0; }
213
223 int64_t nanoseconds() const { return _ns; }
224
232 double toSecondsDouble() const {
233 return isValid() ? static_cast<double>(_ns) / 1'000'000'000.0 : 0.0;
234 }
235
243 bool isZero() const { return _ns == 0; }
244
252 bool isNegative() const { return isValid() && _ns < 0; }
253
261 String toString() const;
262
284 static Result<Duration> fromString(const String &str);
285
295 String toScaledString(int precision = 2) const;
296
298 Duration operator+(const Duration &o) const {
299 if (!isValid() || !o.isValid()) return Duration();
300 return Duration(_ns + o._ns);
301 }
303 Duration operator-(const Duration &o) const {
304 if (!isValid() || !o.isValid()) return Duration();
305 return Duration(_ns - o._ns);
306 }
308 Duration operator*(int64_t s) const {
309 if (!isValid()) return Duration();
310 return Duration(_ns * s);
311 }
313 Duration operator/(int64_t s) const {
314 if (!isValid()) return Duration();
315 return Duration(_ns / s);
316 }
318 Duration operator-() const {
319 if (!isValid()) return Duration();
320 return Duration(-_ns);
321 }
322
324 bool operator==(const Duration &o) const { return _ns == o._ns; }
326 bool operator!=(const Duration &o) const { return _ns != o._ns; }
328 bool operator<(const Duration &o) const { return _ns < o._ns; }
330 bool operator>(const Duration &o) const { return _ns > o._ns; }
332 bool operator<=(const Duration &o) const { return _ns <= o._ns; }
334 bool operator>=(const Duration &o) const { return _ns >= o._ns; }
335
336 private:
337 explicit Duration(int64_t ns) : _ns(ns) {}
338 int64_t _ns = Invalid;
339};
340
341PROMEKI_NAMESPACE_END
342
359template <> struct std::formatter<promeki::Duration> {
360 enum class Style {
361 Hms,
362 Scaled
363 };
364
365 Style _style = Style::Hms;
366 std::formatter<std::string_view> _base;
367
368 constexpr auto parse(std::format_parse_context &ctx) {
369 auto it = ctx.begin();
370 auto end = ctx.end();
371
372 auto tryKeyword = [&](const char *kw, Style s) {
373 auto p = it;
374 while (*kw && p != end && *p == *kw) {
375 ++p;
376 ++kw;
377 }
378 if (*kw == 0 && (p == end || *p == '}' || *p == ':')) {
379 it = p;
380 _style = s;
381 return true;
382 }
383 return false;
384 };
385
386 if (!tryKeyword("scaled", Style::Scaled)) {
387 tryKeyword("hms", Style::Hms);
388 }
389
390 if (it != end && *it == ':') ++it;
391
392 ctx.advance_to(it);
393 return _base.parse(ctx);
394 }
395
396 template <typename FormatContext> auto format(const promeki::Duration &d, FormatContext &ctx) const {
397 promeki::String s = (_style == Style::Scaled) ? d.toScaledString() : d.toString();
398 return _base.format(std::string_view(s.cstr(), s.byteCount()), ctx);
399 }
400};
401
402#endif // PROMEKI_ENABLE_CORE