287 lines
10 KiB
C++
287 lines
10 KiB
C++
// Copyright 2025 Google LLC. All Rights Reserved. This file and proprietary
|
|
// source code may only be used and distributed under the Widevine License
|
|
// Agreement.
|
|
#ifndef WVCDM_UTIL_WV_DURATION_H_
|
|
#define WVCDM_UTIL_WV_DURATION_H_
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <chrono>
|
|
#include <ostream>
|
|
#include <ratio>
|
|
#include <string>
|
|
|
|
#include "wv_class_utils.h"
|
|
|
|
namespace wvutil {
|
|
// Wrappers around various std::chono::duration units.
|
|
using Nanoseconds = std::chrono::nanoseconds;
|
|
using Microseconds = std::chrono::microseconds;
|
|
using Milliseconds = std::chrono::milliseconds;
|
|
using Seconds = std::chrono::seconds;
|
|
using Minutes = std::chrono::minutes;
|
|
using Hours = std::chrono::hours;
|
|
#if __cplusplus >= 202002L // C++20
|
|
using Days = std::chrono::days;
|
|
#else
|
|
// Days is not declared in C++17, the standard C++ library
|
|
// uses the following implementation for C++20.
|
|
using Days = std::chrono::duration<int64_t, std::ratio<86400> >;
|
|
#endif
|
|
|
|
// A high-level duration struct for storing a duration and
|
|
// easily accessing the components.
|
|
// A duration measures a concrete amount of time between two
|
|
// different points in time.
|
|
//
|
|
// Precision of Duration is in milliseconds.
|
|
class Duration final {
|
|
public:
|
|
constexpr Duration() = default;
|
|
// Initialize duration from some kind of chrono duration type that
|
|
// can easily convert to milliseconds.
|
|
// Compiler will not allow irreconcilable duration types to be used
|
|
// without caller explicitly chrono::duration_cast<milliseconds>.
|
|
template <class Rep, class Period>
|
|
constexpr Duration(const std::chrono::duration<Rep, Period>& total_duration)
|
|
: total_milliseconds_(total_duration) {}
|
|
WVCDM_CONSTEXPR_DEFAULT_COPY_AND_MOVE(Duration);
|
|
|
|
private:
|
|
// Note: This private section is needed here.
|
|
// clang++ with -Wundefined-inline will complain about certain
|
|
// inline members not being declared before use in other inline
|
|
// methods.
|
|
|
|
// Helper function for performing truncate (round towards zero)
|
|
// operation on chrono::duration types.
|
|
// The standard C++ chrono library does not provide such a function.
|
|
template <class ToDuration, class Rep, class Period>
|
|
static constexpr ToDuration DurationTruncate(
|
|
const std::chrono::duration<Rep, Period>& duration) {
|
|
return duration >= std::chrono::duration<Rep, Period>::zero()
|
|
? std::chrono::floor<ToDuration>(duration)
|
|
: std::chrono::ceil<ToDuration>(duration);
|
|
}
|
|
|
|
// Helper function for performing truncate on Duration class's
|
|
// |total_milliseconds_|, returning it in a chrono::duration type
|
|
// which is specified by template parameter |ToDuration|.
|
|
template <class ToDuration>
|
|
constexpr Duration GetTruncateInternal() const {
|
|
return Duration(DurationTruncate<ToDuration>(total_milliseconds_));
|
|
}
|
|
|
|
public:
|
|
// == Special Initializers ==
|
|
|
|
static constexpr Duration Zero() { return Duration(); }
|
|
static constexpr Duration FromMilliseconds(int64_t milliseconds) {
|
|
return Duration(Milliseconds(milliseconds));
|
|
}
|
|
static constexpr Duration FromSeconds(int64_t seconds) {
|
|
return Duration(Seconds(seconds));
|
|
}
|
|
|
|
constexpr bool IsZero() const {
|
|
return total_milliseconds_ == Milliseconds::zero();
|
|
}
|
|
constexpr bool IsNegative() const {
|
|
return total_milliseconds_ < Milliseconds::zero();
|
|
}
|
|
constexpr bool IsPositive() const {
|
|
return total_milliseconds_ > Milliseconds::zero();
|
|
}
|
|
constexpr bool IsNonNegative() const {
|
|
return total_milliseconds_ >= Milliseconds::zero();
|
|
}
|
|
|
|
// Basic accessor and conversions (rounds down).
|
|
constexpr Milliseconds total_milliseconds() const {
|
|
return total_milliseconds_;
|
|
}
|
|
constexpr Seconds total_seconds() const {
|
|
return DurationTruncate<Seconds>(total_milliseconds_);
|
|
}
|
|
constexpr Minutes total_minutes() const {
|
|
return DurationTruncate<Minutes>(total_milliseconds_);
|
|
}
|
|
constexpr Hours total_hours() const {
|
|
return DurationTruncate<Hours>(total_milliseconds_);
|
|
}
|
|
constexpr Days total_days() const {
|
|
return DurationTruncate<Days>(total_milliseconds_);
|
|
}
|
|
|
|
// Access duration absolute components bounded within a
|
|
// particular unit.
|
|
// Milliseconds modulo milliseconds per-second (0-999)
|
|
constexpr uint32_t milliseconds() const {
|
|
if (IsNegative()) return GetAbsolute().milliseconds();
|
|
return static_cast<uint32_t>(
|
|
(total_milliseconds() - total_seconds()).count());
|
|
}
|
|
// Seconds modulo seconds per-minute (0-59)
|
|
constexpr uint32_t seconds() const {
|
|
if (IsNegative()) return GetAbsolute().seconds();
|
|
return static_cast<uint32_t>((total_seconds() - total_minutes()).count());
|
|
}
|
|
// Minutes modulo minutes per-hour (0-59).
|
|
constexpr uint32_t minutes() const {
|
|
if (IsNegative()) return GetAbsolute().minutes();
|
|
return static_cast<uint32_t>((total_minutes() - total_hours()).count());
|
|
}
|
|
// Hours modulo hours per-day (0-23)
|
|
constexpr uint32_t hours() const {
|
|
if (IsNegative()) return GetAbsolute().hours();
|
|
return static_cast<uint32_t>((total_hours() - total_days()).count());
|
|
}
|
|
// Days (total).
|
|
constexpr uint32_t days() const {
|
|
if (IsNegative()) return GetAbsolute().days();
|
|
return static_cast<uint32_t>(total_days().count());
|
|
}
|
|
|
|
// Obtain the absolute value.
|
|
constexpr Duration GetAbsolute() const {
|
|
return Duration(std::chrono::abs(total_milliseconds_));
|
|
}
|
|
|
|
// Obtain the truncated (math term for rounding towards zero)
|
|
// value by units.
|
|
constexpr Duration GetTruncateBySeconds() const {
|
|
return GetTruncateInternal<Seconds>();
|
|
}
|
|
constexpr Duration GetTruncateByMinutes() const {
|
|
return GetTruncateInternal<Minutes>();
|
|
}
|
|
constexpr Duration GetTruncateByHours() const {
|
|
return GetTruncateInternal<Hours>();
|
|
}
|
|
constexpr Duration GetTruncateByDays() const {
|
|
return GetTruncateInternal<Days>();
|
|
}
|
|
|
|
// Comparison operators (between another Duration class)
|
|
constexpr bool IsEqualTo(const Duration& other) const {
|
|
return total_milliseconds_ == other.total_milliseconds_;
|
|
}
|
|
constexpr int64_t CompareTo(const Duration& other) const {
|
|
return static_cast<int64_t>(total_milliseconds_.count() -
|
|
other.total_milliseconds_.count());
|
|
}
|
|
WVCDM_DEFINE_CONSTEXPR_EQ_AND_CMP_OPERATORS(Duration);
|
|
|
|
// Comparison operators (between other duration types)
|
|
template <class Rep, class Period>
|
|
constexpr bool operator==(
|
|
const std::chrono::duration<Rep, Period>& other) const {
|
|
return total_milliseconds_ == other;
|
|
}
|
|
template <class Rep, class Period>
|
|
constexpr bool operator!=(
|
|
const std::chrono::duration<Rep, Period>& other) const {
|
|
return total_milliseconds_ != other;
|
|
}
|
|
template <class Rep, class Period>
|
|
constexpr bool operator<=(
|
|
const std::chrono::duration<Rep, Period>& other) const {
|
|
return total_milliseconds_ <= other;
|
|
}
|
|
template <class Rep, class Period>
|
|
constexpr bool operator<(
|
|
const std::chrono::duration<Rep, Period>& other) const {
|
|
return total_milliseconds_ < other;
|
|
}
|
|
template <class Rep, class Period>
|
|
constexpr bool operator>=(
|
|
const std::chrono::duration<Rep, Period>& other) const {
|
|
return total_milliseconds_ >= other;
|
|
}
|
|
template <class Rep, class Period>
|
|
constexpr bool operator>(
|
|
const std::chrono::duration<Rep, Period>& other) const {
|
|
return total_milliseconds_ > other;
|
|
}
|
|
|
|
// Unary plus/minus operators
|
|
constexpr Duration operator+() const { return Duration(total_milliseconds_); }
|
|
constexpr Duration operator-() const {
|
|
return Duration(-total_milliseconds_);
|
|
}
|
|
|
|
// Add/subtract operators (between another Duration class)
|
|
constexpr Duration operator+(const Duration& other) const {
|
|
return Duration(total_milliseconds_ + other.total_milliseconds_);
|
|
}
|
|
constexpr Duration operator-(const Duration& other) const {
|
|
return Duration(total_milliseconds_ - other.total_milliseconds_);
|
|
}
|
|
|
|
// Add/subtract operators (between other duration types)
|
|
// Note 1: This is intentionally implemented as a member function to
|
|
// force the caller the put the Duration class first in the
|
|
// expression.
|
|
// Note 2: These operators are not defined for duration types that
|
|
// smaller than chrono::milliseconds. This could cause
|
|
// unexpected behavior as operations would be truncated.
|
|
// Ex: (Duration(5s) + 500us + 500us) = Duration(5s)
|
|
// Compiler will not allow such operations.
|
|
template <class Rep, class Period>
|
|
constexpr Duration operator+(
|
|
const std::chrono::duration<Rep, Period>& other) const {
|
|
return Duration(total_milliseconds_ + other);
|
|
}
|
|
template <class Rep, class Period>
|
|
constexpr Duration operator-(
|
|
const std::chrono::duration<Rep, Period>& other) const {
|
|
return Duration(total_milliseconds_ - other);
|
|
}
|
|
|
|
// Increment/decrement operators (between another Duration class)
|
|
constexpr Duration& operator+=(const Duration& other) {
|
|
total_milliseconds_ += other.total_milliseconds_;
|
|
return *this;
|
|
}
|
|
constexpr Duration& operator-=(const Duration& other) {
|
|
total_milliseconds_ -= other.total_milliseconds_;
|
|
return *this;
|
|
}
|
|
|
|
// Increment/decrement operators (between another duration types)
|
|
// Note: These operators are not defined for duration types that
|
|
// smaller than chrono::milliseconds (see '+' operator
|
|
// comment for details).
|
|
template <class Rep, class Period>
|
|
constexpr Duration& operator+=(
|
|
const std::chrono::duration<Rep, Period>& other) {
|
|
total_milliseconds_ += other;
|
|
return *this;
|
|
}
|
|
template <class Rep, class Period>
|
|
constexpr Duration& operator-=(
|
|
const std::chrono::duration<Rep, Period>& other) {
|
|
total_milliseconds_ -= other;
|
|
return *this;
|
|
}
|
|
|
|
// To string operator.
|
|
// Converts the Duration to its string representation.
|
|
// Examples:
|
|
// Duration::FromMilliseconds(4000123).ToString()
|
|
// ==> "1h6m40s123ms"
|
|
// Duration::FromSeconds(4000).ToString()
|
|
// ==> "1h6m40s"
|
|
bool PrintTo(std::ostream* out) const;
|
|
std::string ToString() const;
|
|
|
|
private:
|
|
// Internally, the Duration class stores durations in milliseconds.
|
|
Milliseconds total_milliseconds_ = Milliseconds::zero();
|
|
}; // class Duration
|
|
|
|
// == GTest Printer ==
|
|
void PrintTo(const Duration& duration, std::ostream* out);
|
|
} // namespace wvutil
|
|
#endif // WVCDM_UTIL_WV_DURATION_H_
|