11#include <promeki/config.h>
12#if PROMEKI_ENABLE_CORE
21PROMEKI_NAMESPACE_BEGIN
43 PROMEKI_DATATYPE(Duration, DataTypeDuration, 1)
51 static constexpr int64_t Invalid = INT64_MIN;
54 Error writeToStream(DataStream &s) const;
56 template <uint32_t V> static Result<Duration> readFromStream(DataStream &s);
64 static Duration zero() {
return Duration(int64_t{0}); }
71 static Duration fromHours(int64_t h) {
72 return Duration(h * 3'600'000'000'000LL);
80 static Duration fromMinutes(int64_t m) {
81 return Duration(m * 60'000'000'000LL);
89 static Duration fromSeconds(int64_t s) {
90 return Duration(s * 1'000'000'000LL);
98 static Duration fromMilliseconds(int64_t ms) {
99 return Duration(ms * 1'000'000LL);
107 static Duration fromMicroseconds(int64_t us) {
108 return Duration(us * 1'000LL);
116 static Duration fromNanoseconds(int64_t ns) {
return Duration(ns); }
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));
138 template <
typename Float, std::enable_if_t<std::is_
floating_po
int_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));
154 template <
typename T>
static Duration fromSamples(int64_t count,
const Rational<T> &rate) {
155 if (!rate.isValid() || rate.numerator() == 0) {
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);
164 Duration() =
default;
167 bool isValid()
const {
return _ns != Invalid; }
176 int64_t hours()
const {
return isValid() ? _ns / 3'600'000'000'000LL : 0; }
185 int64_t minutes()
const {
return isValid() ? _ns / 60'000'000'000LL : 0; }
194 int64_t seconds()
const {
return isValid() ? _ns / 1'000'000'000LL : 0; }
203 int64_t milliseconds()
const {
return isValid() ? _ns / 1'000'000LL : 0; }
212 int64_t microseconds()
const {
return isValid() ? _ns / 1'000LL : 0; }
223 int64_t nanoseconds()
const {
return _ns; }
232 double toSecondsDouble()
const {
233 return isValid() ?
static_cast<double>(_ns) / 1'000'000'000.0 : 0.0;
243 bool isZero()
const {
return _ns == 0; }
252 bool isNegative()
const {
return isValid() && _ns < 0; }
261 String toString()
const;
284 static Result<Duration> fromString(
const String &str);
295 String toScaledString(
int precision = 2)
const;
298 Duration operator+(
const Duration &o)
const {
299 if (!isValid() || !o.isValid())
return Duration();
300 return Duration(_ns + o._ns);
303 Duration operator-(
const Duration &o)
const {
304 if (!isValid() || !o.isValid())
return Duration();
305 return Duration(_ns - o._ns);
308 Duration operator*(int64_t s)
const {
309 if (!isValid())
return Duration();
310 return Duration(_ns * s);
313 Duration operator/(int64_t s)
const {
314 if (!isValid())
return Duration();
315 return Duration(_ns / s);
318 Duration operator-()
const {
319 if (!isValid())
return Duration();
320 return Duration(-_ns);
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; }
337 explicit Duration(int64_t ns) : _ns(ns) {}
338 int64_t _ns = Invalid;
359template <>
struct std::formatter<promeki::Duration> {
365 Style _style = Style::Hms;
366 std::formatter<std::string_view> _base;
368 constexpr auto parse(std::format_parse_context &ctx) {
369 auto it = ctx.begin();
370 auto end = ctx.end();
372 auto tryKeyword = [&](
const char *kw, Style s) {
374 while (*kw && p != end && *p == *kw) {
378 if (*kw == 0 && (p == end || *p ==
'}' || *p ==
':')) {
386 if (!tryKeyword(
"scaled", Style::Scaled)) {
387 tryKeyword(
"hms", Style::Hms);
390 if (it != end && *it ==
':') ++it;
393 return _base.parse(ctx);
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);