OEMCrypto and OPK v20 prerelease initial commit
This commit is contained in:
78
util/include/buffer_reader.h
Normal file
78
util/include/buffer_reader.h
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 2018 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_BUFFER_READER_H_
|
||||
#define WVCDM_UTIL_BUFFER_READER_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "wv_class_utils.h"
|
||||
|
||||
namespace wvutil {
|
||||
// Annotate a function indicating the caller must examine the return value.
|
||||
// Use like:
|
||||
// int foo() WARN_UNUSED_RESULT;
|
||||
// To explicitly ignore a result, see |ignore_result()| in <base/basictypes.h>.
|
||||
#if defined(COMPILER_GCC)
|
||||
# define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||
#else
|
||||
# define WARN_UNUSED_RESULT
|
||||
#endif
|
||||
|
||||
class BufferReader {
|
||||
public:
|
||||
BufferReader() = delete;
|
||||
WVCDM_DISALLOW_COPY_AND_MOVE(BufferReader);
|
||||
|
||||
BufferReader(const uint8_t* buf, size_t size)
|
||||
: buf_(buf), size_(buf != nullptr ? size : 0) {}
|
||||
|
||||
// == Accessors ==
|
||||
|
||||
constexpr const uint8_t* data() const { return buf_; }
|
||||
constexpr size_t size() const { return size_; }
|
||||
constexpr size_t pos() const { return pos_; }
|
||||
|
||||
constexpr size_t BytesRemaining() const {
|
||||
return size_ >= pos_ ? size_ - pos_ : 0;
|
||||
}
|
||||
|
||||
constexpr bool HasBytes(size_t count) const {
|
||||
return count <= BytesRemaining();
|
||||
}
|
||||
constexpr bool IsEof() const { return pos_ >= size_; }
|
||||
|
||||
// Read a value from the stream, performing endian correction,
|
||||
// and advance the stream pointer.
|
||||
bool Read1(uint8_t* v) WARN_UNUSED_RESULT;
|
||||
bool Read2(uint16_t* v) WARN_UNUSED_RESULT;
|
||||
bool Read2s(int16_t* v) WARN_UNUSED_RESULT;
|
||||
bool Read4(uint32_t* v) WARN_UNUSED_RESULT;
|
||||
bool Read4s(int32_t* v) WARN_UNUSED_RESULT;
|
||||
bool Read8(uint64_t* v) WARN_UNUSED_RESULT;
|
||||
bool Read8s(int64_t* v) WARN_UNUSED_RESULT;
|
||||
|
||||
bool ReadString(std::string* str, size_t count) WARN_UNUSED_RESULT;
|
||||
bool ReadVec(std::vector<uint8_t>* t, size_t count) WARN_UNUSED_RESULT;
|
||||
|
||||
// These variants read a 4-byte integer of the corresponding signedness and
|
||||
// store it in the 8-byte return type.
|
||||
bool Read4Into8(uint64_t* v) WARN_UNUSED_RESULT;
|
||||
bool Read4sInto8s(int64_t* v) WARN_UNUSED_RESULT;
|
||||
|
||||
// Advance the stream by this many bytes.
|
||||
bool SkipBytes(size_t count) WARN_UNUSED_RESULT;
|
||||
|
||||
private:
|
||||
const uint8_t* buf_ = nullptr;
|
||||
size_t size_ = 0;
|
||||
size_t pos_ = 0;
|
||||
|
||||
template <typename T>
|
||||
bool Read(T* t) WARN_UNUSED_RESULT;
|
||||
}; // class BufferReader
|
||||
} // namespace wvutil
|
||||
#endif // WVCDM_UTIL_BUFFER_READER_H_
|
||||
@@ -9,18 +9,19 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace wvutil {
|
||||
#include "wv_timestamp.h"
|
||||
|
||||
namespace wvutil {
|
||||
// Provides time related information. The implementation is platform dependent.
|
||||
class Clock {
|
||||
public:
|
||||
Clock() {}
|
||||
virtual ~Clock() {}
|
||||
Clock() = default;
|
||||
virtual ~Clock() = default;
|
||||
|
||||
// Provides the number of seconds since an epoch - 01/01/1970 00:00 UTC
|
||||
virtual int64_t GetCurrentTime();
|
||||
|
||||
virtual Timestamp GetCurrentTimestamp();
|
||||
};
|
||||
|
||||
} // namespace wvutil
|
||||
|
||||
#endif // WVCDM_UTIL_CLOCK_H_
|
||||
|
||||
211
util/include/hls_attribute_list.h
Normal file
211
util/include/hls_attribute_list.h
Normal file
@@ -0,0 +1,211 @@
|
||||
// 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_HLS_ATTRIBUTE_LIST_H_
|
||||
#define WVCDM_UTIL_HLS_ATTRIBUTE_LIST_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "wv_class_utils.h"
|
||||
|
||||
namespace wvutil {
|
||||
// An HLS Attribute List is a loosely defined HLS tag value
|
||||
// type representing a dictionary of attribute name-value pairs.
|
||||
// No attribute name may appear twice in a valid HLS Attribute
|
||||
// List.
|
||||
//
|
||||
// When serialized, an HLS attribute list appears as a comma
|
||||
// separated list of <name>=<value> pairs, without any line breaks,
|
||||
// and whitespace only within quoted string attribute values.
|
||||
//
|
||||
// The HLS specification defines them as context sensitive-types,
|
||||
// as the format of certain value types are ambiguous with other
|
||||
// value types (ex. something that looks like a hex sequence could
|
||||
// actually be an enum string). The exact value types of attributes
|
||||
// depends on the HLS tag.
|
||||
//
|
||||
// This implementation is intended to be context free when parsing.
|
||||
// Internally, value will be assigned a type based on their
|
||||
// appearance to the most restrictive type; however, accessing as a
|
||||
// particular type will be allowed so long as they match the format
|
||||
// that type. The only exception to this is quoted strings, which
|
||||
// are fully unambiguous with all other types.
|
||||
//
|
||||
// The standard HLS attribute list allows for UTF-8 encoded unicode
|
||||
// characters; however, for Widevine's use case, we only allow
|
||||
// basic ASCII.
|
||||
//
|
||||
// This class is based on RFC 8216 section 4.2.
|
||||
class HlsAttributeList {
|
||||
public:
|
||||
enum ValueType {
|
||||
kUnsetType = 0,
|
||||
// HLS integers are a sequence of 1 to 20 base10 digits
|
||||
// values, which must fit into an unsigned 64-bit integer.
|
||||
// Note:
|
||||
// All integers can appear as an enum string.
|
||||
// All integers can appear as floats; however, precision
|
||||
// restrictions may limit ability to parse accurately.
|
||||
kIntegerType,
|
||||
// HLS hex sequence are a sequence of 1 or more upper case
|
||||
// hexadecimal digits, with the prefix "0x" or "0X".
|
||||
// Note:
|
||||
// All hex sequences can appear as an enum string.
|
||||
// Certain hex sequences can appear as a resolution.
|
||||
kHexSequenceType,
|
||||
// HLS float and sign float are a sequence of base10 digits
|
||||
// with a possible leading negative sign ('-') and at most one
|
||||
// decimal point ('.').
|
||||
// Note:
|
||||
// All floats can appear as an enum string.
|
||||
// Certain floats can appear are an integer.
|
||||
kFloatType,
|
||||
// For simplicity, signed and unsigned floats are internally
|
||||
// treated as the same.
|
||||
kSignedFloatType = kFloatType, // Aliasing
|
||||
// HLS quoted strings are a sequence of printable characters
|
||||
// (except a double quote), or space characters, contained within
|
||||
// a pair of double quotes.
|
||||
// Note: Quote string are unambiguous with all other types.
|
||||
kQuotedStringType,
|
||||
// HLS enum strings are a sequence of any printable characters
|
||||
// (except quotes or commas) and do not contain whitespace.
|
||||
// Note:
|
||||
// Certain enum strings can appear as integers, floats, hex
|
||||
// sequences or resolutions.
|
||||
kEnumStringType,
|
||||
// HLS resolutions are a pair of base10 integers (similar to
|
||||
// integer types) separated by an 'x' character.
|
||||
// Note:
|
||||
// All resolutions can appear as enum strings
|
||||
// Certain resolutions can appear as hex sequences.
|
||||
kResolutionType,
|
||||
};
|
||||
static const char* ValueTypeToString(ValueType type);
|
||||
|
||||
// Checks if the provided |name| is valid HLS attribute name.
|
||||
static bool IsValidName(const std::string& name);
|
||||
|
||||
// Checks if the provided |value| is a valid HLS enumerated
|
||||
// string.
|
||||
static bool IsValidEnumStringValue(const std::string& value);
|
||||
// Checks if the provided |value| is an allowed content
|
||||
// of a quote string (i.e., |value| is the portion that is
|
||||
// to be contained within the double quotes).
|
||||
static bool IsValidQuotedStringValue(const std::string& value);
|
||||
|
||||
// Validator for an HLS unsigned integer representation.
|
||||
// Checks that the value representation |value_rep| conforms
|
||||
// to HLS requirements for a serialized integer.
|
||||
static bool IsValidIntegerRep(const std::string& value_rep);
|
||||
// Parses the provided |integer_rep| as an HLS integer, assign
|
||||
// the parsed integer to |value|.
|
||||
static bool ParseInteger(const std::string& integer_rep, uint64_t* value);
|
||||
|
||||
HlsAttributeList() = default;
|
||||
WVCDM_DEFAULT_COPY_AND_MOVE(HlsAttributeList);
|
||||
|
||||
// == Basic Accessors ==
|
||||
bool IsEmpty() const { return members_.empty(); }
|
||||
size_t Count() const { return members_.size(); }
|
||||
void Clear() { members_.clear(); }
|
||||
|
||||
// == Value Getters ==
|
||||
|
||||
// Returns a list of attribute names.
|
||||
std::vector<std::string> GetNames() const;
|
||||
// Returns true if the provided attribute |name| is contained
|
||||
// within list.
|
||||
bool Contains(const std::string& name) const;
|
||||
|
||||
// Checks if the provided attribute |name| could be the
|
||||
// specified |type|.
|
||||
// Certain value types are ambiguous; so they may be marked
|
||||
// internally as one type, but are still valid forms of a
|
||||
// different type.
|
||||
bool IsType(const std::string& name, ValueType type) const;
|
||||
|
||||
// Gets the attribute value for the provided attribute |name|,
|
||||
// assigning the deserialized value to the output parameter(s).
|
||||
//
|
||||
// If a type is internally stored as a different type, but the format
|
||||
// matches the requested type, it will be allowed.
|
||||
//
|
||||
// Returns true if the attribute value was successfully obtained;
|
||||
// false otherwise (attribute does not exist, or the value could
|
||||
// not be parsed as the specified type).
|
||||
bool GetEnumString(const std::string& name, std::string* value) const;
|
||||
bool GetQuotedString(const std::string& name, std::string* value) const;
|
||||
bool GetHexSequence(const std::string& name, std::string* value) const;
|
||||
bool GetHexSequence(const std::string& name,
|
||||
std::vector<uint8_t>* value) const;
|
||||
bool GetInteger(const std::string& name, uint64_t* value) const;
|
||||
bool GetFloat(const std::string& name, double* value) const;
|
||||
bool GetResolution(const std::string& name, uint64_t* width,
|
||||
uint64_t* height) const;
|
||||
|
||||
// == Value Setters ==
|
||||
|
||||
// The value setters attempt to serializes the provided value
|
||||
// into an HLS attribute value format of the type indicated
|
||||
// by the method name. These methods will overwrite any existing
|
||||
// attribute of the same name.
|
||||
// Setting will be rejected if |name| is not a valid HLS attribute
|
||||
// name, or if the provided |value| is valid (only applicable to
|
||||
// certain types).
|
||||
bool SetEnumString(const std::string& name, const std::string& value);
|
||||
bool SetQuotedString(const std::string& name, const std::string& value);
|
||||
// Note: This implementation will use lower "0x" prefix for
|
||||
// hex sequences.
|
||||
bool SetHexSequence(const std::string& name, const std::string& value);
|
||||
bool SetHexSequence(const std::string& name,
|
||||
const std::vector<uint8_t>& value);
|
||||
bool SetInteger(const std::string& name, uint64_t value);
|
||||
bool SetFloat(const std::string& name, double value);
|
||||
bool SetResolution(const std::string& name, uint64_t width, uint64_t height);
|
||||
|
||||
// Removes the specified attribute. Returns true if the attribute
|
||||
// was removed; false otherwise.
|
||||
bool Remove(const std::string& name);
|
||||
|
||||
// == Parsing / Serialization ==
|
||||
|
||||
// Attempts to parse the provided HLS Attribute List.
|
||||
// Always clears the existing contents, even if the attribute
|
||||
// list cannot be parsed.
|
||||
//
|
||||
// Internally, values are not parsed, but checked to see which
|
||||
// type they resemble. This does not restrict accessing them
|
||||
// as different types.
|
||||
//
|
||||
// Returns true if successfully parsed; false otherwise.
|
||||
bool Parse(const std::string& hls_attr_list_rep);
|
||||
|
||||
// Serializes the contents of the HLS attribute list into a
|
||||
// valid HLS attribute list form.
|
||||
std::string Serialize() const;
|
||||
bool SerializeToStream(std::ostream* out) const;
|
||||
|
||||
// Internally, values are stored in their serialized form
|
||||
// in case their value is ambiguous between two or more types.
|
||||
// The assigned ValueType is intended to be a hint for improve
|
||||
// access speeds.
|
||||
using ValueInfo =
|
||||
std::pair</* type hint */ ValueType, /* value rep */ std::string>;
|
||||
|
||||
private:
|
||||
// Internal utility to obtain the value info.
|
||||
// Silently returns null if the name does not exist.
|
||||
const ValueInfo* GetInfo(const std::string& name) const;
|
||||
|
||||
// Values in |members_| will always be validated before assigned.
|
||||
std::map</* name */ std::string, ValueInfo> members_;
|
||||
}; // class HlsAttributeList
|
||||
} // namespace wvutil
|
||||
#endif // WVCDM_UTIL_HLS_ATTRIBUTE_LIST_H_
|
||||
@@ -1,65 +0,0 @@
|
||||
// Copyright 2019 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_RW_LOCK_H_
|
||||
#define WVCDM_UTIL_RW_LOCK_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
#include "disallow_copy_and_assign.h"
|
||||
#include "util_common.h"
|
||||
|
||||
namespace wvutil {
|
||||
|
||||
// A simple reader-writer mutex implementation that mimics the one from C++17
|
||||
class shared_mutex {
|
||||
public:
|
||||
shared_mutex() : reader_count_(0), has_writer_(false) {}
|
||||
~shared_mutex();
|
||||
|
||||
// These methods take the mutex as a reader. They do not fulfill the
|
||||
// SharedMutex requirement from the C++14 STL, but they fulfill enough of it
|
||||
// to be used with |shared_lock| below.
|
||||
void lock_shared();
|
||||
void unlock_shared();
|
||||
|
||||
// These methods take the mutex as a writer. They fulfill the Mutex
|
||||
// requirement from the C++11 STL so that this mutex can be used with
|
||||
// |std::unique_lock|.
|
||||
void lock() { lock_implementation(false); }
|
||||
bool try_lock() { return lock_implementation(true); }
|
||||
void unlock();
|
||||
|
||||
private:
|
||||
bool lock_implementation(bool abort_if_unavailable);
|
||||
|
||||
uint32_t reader_count_;
|
||||
bool has_writer_;
|
||||
|
||||
std::mutex mutex_;
|
||||
std::condition_variable condition_variable_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(shared_mutex);
|
||||
};
|
||||
|
||||
// A simple reader lock implementation that mimics the one from C++14
|
||||
template <typename Mutex>
|
||||
class shared_lock {
|
||||
public:
|
||||
explicit shared_lock(Mutex& lock) : lock_(&lock) { lock_->lock_shared(); }
|
||||
explicit shared_lock(Mutex* lock) : lock_(lock) { lock_->lock_shared(); }
|
||||
~shared_lock() { lock_->unlock_shared(); }
|
||||
|
||||
private:
|
||||
Mutex* lock_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(shared_lock);
|
||||
};
|
||||
|
||||
} // namespace wvutil
|
||||
|
||||
#endif // WVCDM_UTIL_RW_LOCK_H_
|
||||
89
util/include/string_utils.h
Normal file
89
util/include/string_utils.h
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright 2024 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_STRING_UTILS_H_
|
||||
#define WVCDM_UTIL_STRING_UTILS_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Small set of simple string utilities.
|
||||
//
|
||||
// It is inspired by Python strings and Abseil. The CDM tends to not
|
||||
// be too fancy with its use of templated containers; none of the
|
||||
// Abseil container magic is not provided, nor are the fancy templated
|
||||
// configurations.
|
||||
namespace wvutil {
|
||||
|
||||
// Splits a string into several substrings based on the provided
|
||||
// delimiter.
|
||||
//
|
||||
// Special cases:
|
||||
// - An empty delimiter will split the string into each character.
|
||||
std::vector<std::string> StringSplit(const std::string& s, char delim);
|
||||
std::vector<std::string> StringSplit(const std::string& s,
|
||||
const std::string& delim);
|
||||
std::vector<std::string> StringSplit(const std::string& s, const char* delim);
|
||||
|
||||
// Joins a list of strings into a single string, using the specified
|
||||
// "glue" character(s) between tokens. Note: |glue| can be empty.
|
||||
std::string StringJoin(const std::vector<std::string>& tokens, char glue);
|
||||
std::string StringJoin(const std::vector<std::string>& tokens,
|
||||
const std::string& glue = "");
|
||||
std::string StringJoin(const std::vector<std::string>& tokens,
|
||||
const char* glue);
|
||||
|
||||
// Counts the number of instances of |needle| sequences found in the
|
||||
// |haystack|.
|
||||
//
|
||||
// Special cases:
|
||||
// - An empty needle will return the length of |haystack| plus 1,
|
||||
// including for an empty string.
|
||||
// Note: This is a convention used by many string utility
|
||||
// libraries.
|
||||
size_t StringCount(const std::string& haystack, char needle);
|
||||
size_t StringCount(const std::string& haystack, const std::string& needle);
|
||||
size_t StringCount(const std::string& haystack, const char* needle);
|
||||
|
||||
// Checks if any instances of |needle| sequences found in the |haystack|.
|
||||
//
|
||||
// Special cases:
|
||||
// - An empty |needle| is always present, even if |haystack| is empty.
|
||||
// Note: This is a convention used by many string utility
|
||||
// libraries.
|
||||
bool StringContains(const std::string& haystack, char needle);
|
||||
bool StringContains(const std::string& haystack, const std::string& needle);
|
||||
bool StringContains(const std::string& haystack, const char* needle);
|
||||
|
||||
// Checks if the |needle| sequences found at the beginning of |haystack|.
|
||||
//
|
||||
// Special cases:
|
||||
// - An empty |needle| is always present, even if |haystack| is empty.
|
||||
// Note: This is a convention used by many string utility
|
||||
// libraries.
|
||||
bool StringStartsWith(const std::string& haystack, char needle);
|
||||
bool StringStartsWith(const std::string& haystack, const std::string& needle);
|
||||
bool StringStartsWith(const std::string& haystack, const char* needle);
|
||||
|
||||
// Checks if the |needle| sequences found at the end of |haystack|.
|
||||
//
|
||||
// Special cases:
|
||||
// - An empty |needle| is always present, even if |haystack| is empty.
|
||||
// Note: This is a convention used by many string utility
|
||||
// libraries.
|
||||
bool StringEndsWith(const std::string& haystack, char needle);
|
||||
bool StringEndsWith(const std::string& haystack, const std::string& needle);
|
||||
bool StringEndsWith(const std::string& haystack, const char* needle);
|
||||
|
||||
// Removes any leading or trailing white space from the provided string.
|
||||
std::string StringTrim(const std::string& s);
|
||||
|
||||
// Checks if the vector of strings contains any instance of the
|
||||
// specified |needle|.
|
||||
//
|
||||
// Note: Unlike the other utilities, an empty |needle| is treated
|
||||
// as a value.
|
||||
bool StringVecContains(const std::vector<std::string>& haystack,
|
||||
const std::string& needle);
|
||||
} // namespace wvutil
|
||||
#endif // WVCDM_UTIL_STRING_UTILS_H_
|
||||
223
util/include/wv_date_time.h
Normal file
223
util/include/wv_date_time.h
Normal file
@@ -0,0 +1,223 @@
|
||||
// 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_DATE_TIME_H_
|
||||
#define WVCDM_UTIL_DATE_TIME_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
#include "wv_class_utils.h"
|
||||
#include "wv_duration.h"
|
||||
#include "wv_timestamp.h"
|
||||
|
||||
namespace wvutil {
|
||||
// The DateTime class represents a time point measured in UTC
|
||||
// Gregorian calendar dates and 24-hour timekeeping system.
|
||||
//
|
||||
// Internally, the time is measured in Unix Time (milliseconds
|
||||
// since January 1st, 1970 (epoch)).
|
||||
//
|
||||
// For the CDM, we are not concerned about time points before
|
||||
// January 1st, 1970; this class does not support negative epoch
|
||||
// seconds. In addition, zero is treated as a special value
|
||||
// which indicates an uninitialized time point.
|
||||
//
|
||||
// Min DateTime: 1970-01-01 00:00:00.001 (epoch ms = 1)
|
||||
// Max DateTime: 9999-12-31 23:59:59.999 (epoch ms = 253402300799999)
|
||||
//
|
||||
// Converting from Unix Time to datetime components is a potentially
|
||||
// expensive operation for their amount of utility; to reduce this
|
||||
// overhead date components are calculated once per change, and stored
|
||||
// individually.
|
||||
//
|
||||
// For testing, use the DateTime::Builder class for create DateTime
|
||||
// instances from their individual components.
|
||||
//
|
||||
// The DateTime class provides a PrintTo()/ToString() method which
|
||||
// returns an initialized DateTime in ISO 8601 format without timezone
|
||||
// indicator and with milliseconds only being printed if non-zero.
|
||||
// Use DateTime::Formatter for specific formatting needs.
|
||||
class DateTime {
|
||||
public:
|
||||
constexpr DateTime() = default; // Uninitialized DateTime.
|
||||
WVCDM_CONSTEXPR_DEFAULT_COPY_AND_MOVE(DateTime);
|
||||
|
||||
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.
|
||||
template <class ToDuration>
|
||||
constexpr ToDuration EpochFloor() const {
|
||||
return std::chrono::floor<ToDuration>(epoch_milliseconds());
|
||||
}
|
||||
|
||||
public:
|
||||
static DateTime FromTimestamp(const Timestamp& timestamp);
|
||||
|
||||
// Create a DateTime instance from Unix Time in epoch seconds.
|
||||
// Optionally allowed to include |millisecond| (0 to 999).
|
||||
// If |epoch_seconds| or |millisecond| are invalid values, then an
|
||||
// uninitlaized DateTime instance is returned.
|
||||
static DateTime FromUnixSeconds(uint64_t epoch_seconds,
|
||||
uint32_t milliseconds = 0) {
|
||||
return FromTimestamp(
|
||||
Timestamp::FromUnixSeconds(epoch_seconds, milliseconds));
|
||||
}
|
||||
static DateTime FromUnixSeconds(const Seconds& epoch_seconds,
|
||||
uint32_t milliseconds = 0) {
|
||||
return FromTimestamp(
|
||||
Timestamp::FromUnixSeconds(epoch_seconds, milliseconds));
|
||||
}
|
||||
|
||||
// Create a DateTime instance from Unix Time in epoch milliseconds.
|
||||
// If |epoch_milliseconds| is an invalid value (zero), then an
|
||||
// uninitlaized DateTime instance is returned.
|
||||
static DateTime FromUnixMilliseconds(uint64_t epoch_milliseconds) {
|
||||
return FromTimestamp(Timestamp::FromUnixMilliseconds(epoch_milliseconds));
|
||||
}
|
||||
static DateTime FromUnixMilliseconds(const Milliseconds& epoch_milliseconds) {
|
||||
return FromTimestamp(Timestamp::FromUnixMilliseconds(epoch_milliseconds));
|
||||
}
|
||||
|
||||
// Obtain the minimum and maximum representable DateTime.
|
||||
static DateTime Min() { return FromTimestamp(Timestamp::Min()); }
|
||||
static DateTime Max() { return FromTimestamp(Timestamp::Max()); }
|
||||
|
||||
constexpr const Timestamp& timestamp() const { return timestamp_; }
|
||||
|
||||
// == Epoch Accessors ==
|
||||
constexpr Seconds epoch_seconds() const { return timestamp_.epoch_seconds(); }
|
||||
constexpr Milliseconds epoch_milliseconds() const {
|
||||
return timestamp_.epoch_milliseconds();
|
||||
}
|
||||
|
||||
// == Component Accessors ==
|
||||
// Year on Gregorian calendar (1970 - 9999; 0 if unset)
|
||||
constexpr uint32_t year() const { return year_; }
|
||||
// Month of the year (January = 1, December = 12; 0 if unset)
|
||||
constexpr uint32_t month() const { return month_; }
|
||||
// Day of the month (1 - 28/29/30/31; 0 if unset)
|
||||
constexpr uint32_t day() const { return day_; }
|
||||
// Day of the year (1 - 365/366; 0 if unset)
|
||||
constexpr uint32_t day_of_year() const { return day_of_year_; }
|
||||
// Day of the week (1 (Sunday) - 7 (Saturday); 0 if unset)
|
||||
constexpr uint32_t day_of_week() const { return day_of_week_; }
|
||||
|
||||
// Time component accessors.
|
||||
// Hour of day (0 - 23; 0 if unset)
|
||||
constexpr uint32_t hour() const {
|
||||
if (!IsSet()) return 0;
|
||||
return static_cast<uint32_t>(
|
||||
(EpochFloor<Hours>() - EpochFloor<Days>()).count());
|
||||
}
|
||||
// Minute of hour (0 - 59; 0 if unset)
|
||||
constexpr uint32_t minute() const {
|
||||
if (!IsSet()) return 0;
|
||||
return static_cast<uint32_t>(
|
||||
(EpochFloor<Minutes>() - EpochFloor<Hours>()).count());
|
||||
}
|
||||
// Second of minute (0 - 59; 0 if unset)
|
||||
constexpr uint32_t second() const {
|
||||
if (!IsSet()) return 0;
|
||||
return static_cast<uint32_t>(
|
||||
(EpochFloor<Seconds>() - EpochFloor<Minutes>()).count());
|
||||
}
|
||||
// Millisecond of second (0 - 999; 0 if unset)
|
||||
constexpr uint32_t millisecond() const { return timestamp_.milliseconds(); }
|
||||
|
||||
// Checks if the DateTime instance is set.
|
||||
constexpr bool IsSet() const { return timestamp_.IsSet(); }
|
||||
constexpr explicit operator bool() const { return IsSet(); }
|
||||
|
||||
constexpr void Clear() {
|
||||
timestamp_.Clear();
|
||||
ClearComponents();
|
||||
}
|
||||
|
||||
// == Comparison Operators ==
|
||||
constexpr bool IsEqualTo(const DateTime& other) const {
|
||||
return timestamp_.IsEqualTo(other.timestamp_);
|
||||
}
|
||||
constexpr int64_t CompareTo(const DateTime& other) const {
|
||||
return timestamp_.CompareTo(other.timestamp_);
|
||||
}
|
||||
WVCDM_DEFINE_CONSTEXPR_EQ_AND_CMP_OPERATORS(DateTime);
|
||||
|
||||
constexpr bool IsEqualTo(const Timestamp& other) const {
|
||||
return timestamp_.IsEqualTo(other);
|
||||
}
|
||||
constexpr int64_t CompareTo(const Timestamp& other) const {
|
||||
return timestamp_.CompareTo(other);
|
||||
}
|
||||
WVCDM_DEFINE_CONSTEXPR_EQ_AND_CMP_OPERATORS(Timestamp);
|
||||
|
||||
// == Duration Operators ==
|
||||
// Duration-based addition/subtraction operations.
|
||||
// Returns a new DateTime instance with time point adjusted by
|
||||
// the provided Duration.
|
||||
// If current DateTime instance is unset, or if result value
|
||||
// is outside the range of valid DateTime values, then an unset
|
||||
// DateTime is returned.
|
||||
DateTime operator+(const Duration& duration) const;
|
||||
DateTime operator-(const Duration& duration) const;
|
||||
|
||||
// DateTime difference.
|
||||
// Returns the duration between the two provided DateTime
|
||||
// instances.
|
||||
// If either DateTime instance is unset, then the resulting
|
||||
// Duration is zero.
|
||||
Duration operator-(const DateTime& other) const;
|
||||
|
||||
// Duration-based increment/decrement operators.
|
||||
// Increment or decrement the DateTime by the provided Duration
|
||||
// amount.
|
||||
// If current DateTime instance is unset, then no action will
|
||||
// occur. If result value is outside the range of valid DateTime
|
||||
// values, then DateTime will be unset.
|
||||
DateTime& operator+=(const Duration& duration);
|
||||
DateTime& operator-=(const Duration& duration);
|
||||
|
||||
// For initialized DateTime instances, returns the datetime
|
||||
// in ISO 8601 format. Milliseconds are only printed
|
||||
// if non-zero.
|
||||
// An uninitialized DateTime will return an empty string.
|
||||
// Ex:
|
||||
// Without milli: 2024-01-19T14:49:13Z
|
||||
// With milli: 2024-01-19T14:49:13.507Z
|
||||
// Use DateTime::Formatter for more formatting options.
|
||||
bool PrintTo(std::ostream* out) const;
|
||||
std::string ToString() const;
|
||||
|
||||
private:
|
||||
// Special constructor.
|
||||
explicit DateTime(const Timestamp& timestamp);
|
||||
|
||||
// Attempts to calculate subcomponents.
|
||||
// Failure to calculate subcomponents will clear |timestamp_|.
|
||||
void UpdateTimestamp(const Timestamp& new_timestamp);
|
||||
|
||||
constexpr void ClearComponents() {
|
||||
year_ = month_ = day_ = day_of_year_ = day_of_week_ = 0;
|
||||
}
|
||||
|
||||
// Source of truth for DateTime class.
|
||||
Timestamp timestamp_;
|
||||
|
||||
// Components (derived from |timestamp_|).
|
||||
uint16_t year_ = 0;
|
||||
uint8_t month_ = 0;
|
||||
uint8_t day_ = 0;
|
||||
uint16_t day_of_year_ = 0;
|
||||
uint8_t day_of_week_ = 0;
|
||||
}; // class DateTime
|
||||
|
||||
// == GTest Printer ==
|
||||
void PrintTo(const DateTime& date_time, std::ostream* out);
|
||||
} // namespace wvutil
|
||||
#endif // WVCDM_UTIL_DATE_TIME_H_
|
||||
286
util/include/wv_duration.h
Normal file
286
util/include/wv_duration.h
Normal file
@@ -0,0 +1,286 @@
|
||||
// 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_
|
||||
170
util/include/wv_timestamp.h
Normal file
170
util/include/wv_timestamp.h
Normal file
@@ -0,0 +1,170 @@
|
||||
// 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_TIMESTAMP_H_
|
||||
#define WVCDM_UTIL_WV_TIMESTAMP_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "wv_class_utils.h"
|
||||
#include "wv_duration.h"
|
||||
|
||||
namespace wvutil {
|
||||
// The Timestamp class is a light-weight representation of a
|
||||
// time point.
|
||||
//
|
||||
// Internally, the time is measured in Unix Time (milliseconds
|
||||
// since January 1st, 1970 UTC (epoch)).
|
||||
//
|
||||
// For this library, we are not concerned about time points before
|
||||
// January 1st, 1970; this class does not support negative epoch
|
||||
// seconds. In addition, zero is treated as a special value
|
||||
// which indicates an uninitialized time point.
|
||||
//
|
||||
// Min Timestamp: 1970-01-01 00:00:00.001 (epoch ms = 1)
|
||||
// Max Timestamp: 9999-12-31 23:59:59.999 (epoch ms = 253402300799999)
|
||||
class Timestamp {
|
||||
public:
|
||||
constexpr Timestamp() = default; // Defaults to "unset".
|
||||
WVCDM_CONSTEXPR_DEFAULT_COPY_AND_MOVE(Timestamp);
|
||||
|
||||
// Create a Timestamp instance from Unix Time in epoch seconds.
|
||||
// Optionally allowed to include |millisecond| (0 to 999).
|
||||
// If |epoch_seconds| or |millisecond| are invalid values, then an
|
||||
// uninitlaized Timestamp instance is returned.
|
||||
static constexpr Timestamp FromUnixSeconds(uint64_t epoch_seconds,
|
||||
uint32_t milliseconds = 0) {
|
||||
if (milliseconds > 999u) return Timestamp();
|
||||
return Timestamp(Seconds(epoch_seconds) + Milliseconds(milliseconds));
|
||||
}
|
||||
static constexpr Timestamp FromUnixSeconds(const Seconds& epoch_seconds,
|
||||
uint32_t milliseconds = 0) {
|
||||
if (milliseconds > 999u) return Timestamp();
|
||||
return Timestamp(epoch_seconds + Milliseconds(milliseconds));
|
||||
}
|
||||
|
||||
// Create a Timestamp instance from Unix Time in epoch milliseconds.
|
||||
// If |epoch_milliseconds| is an invalid value (zero), then an
|
||||
// uninitlaized Timestamp instance is returned.
|
||||
static constexpr Timestamp FromUnixMilliseconds(uint64_t epoch_milliseconds) {
|
||||
return Timestamp(Milliseconds(epoch_milliseconds));
|
||||
}
|
||||
static constexpr Timestamp FromUnixMilliseconds(
|
||||
const Milliseconds& epoch_milliseconds) {
|
||||
return Timestamp(epoch_milliseconds);
|
||||
}
|
||||
|
||||
// Obtain the minimum and maximum representable Timestamp.
|
||||
static constexpr Timestamp Min() { return Timestamp(kMinMsDuration); }
|
||||
static constexpr Timestamp Max() { return Timestamp(kMaxMsDuration); }
|
||||
|
||||
// == General Accessors ==
|
||||
|
||||
// Get the epoch seconds duration (rounding down milliseconds).
|
||||
constexpr Seconds epoch_seconds() const {
|
||||
return std::chrono::floor<Seconds>(epoch_milliseconds_);
|
||||
}
|
||||
// Get the milliseconds fraction of the epoch time (0-999).
|
||||
constexpr uint32_t milliseconds() const {
|
||||
return static_cast<uint32_t>(
|
||||
(epoch_milliseconds_ - epoch_seconds()).count());
|
||||
}
|
||||
|
||||
constexpr Milliseconds epoch_milliseconds() const {
|
||||
return epoch_milliseconds_;
|
||||
}
|
||||
|
||||
// As noted, the timestamp is considered "unset" if zero.
|
||||
constexpr bool IsSet() const {
|
||||
return epoch_milliseconds_ > Milliseconds::zero();
|
||||
}
|
||||
explicit constexpr operator bool() const { return IsSet(); }
|
||||
|
||||
constexpr void Clear() { epoch_milliseconds_ = kUnsetMsDuration; }
|
||||
|
||||
// == Comparisons ==
|
||||
|
||||
constexpr bool IsEqualTo(const Timestamp& other) const {
|
||||
return epoch_milliseconds_ == other.epoch_milliseconds_;
|
||||
}
|
||||
constexpr int64_t CompareTo(const Timestamp& other) const {
|
||||
return static_cast<int64_t>(epoch_milliseconds_.count() -
|
||||
other.epoch_milliseconds_.count());
|
||||
}
|
||||
WVCDM_DEFINE_CONSTEXPR_EQ_AND_CMP_OPERATORS(Timestamp);
|
||||
|
||||
// == Arithmetic Operations ==
|
||||
|
||||
// Duration-based addition/subtraction operations.
|
||||
// Returns a new Timestamp instance with time point adjusted by
|
||||
// the provided Duration.
|
||||
// If current Timestamp instance is unset, or if result value
|
||||
// is outside the range of valid Timestamp values, then an unset
|
||||
// Timestamp is returned.
|
||||
constexpr Timestamp operator+(const Duration& duration) const {
|
||||
if (!IsSet()) return Timestamp();
|
||||
return Timestamp(epoch_milliseconds_ + duration.total_milliseconds());
|
||||
}
|
||||
constexpr Timestamp operator-(const Duration& duration) const {
|
||||
if (!IsSet()) return Timestamp();
|
||||
return Timestamp(epoch_milliseconds_ - duration.total_milliseconds());
|
||||
}
|
||||
|
||||
// Duration-based increment/decrement operators.
|
||||
// Increment or decrement the Timestamp by the provided Duration
|
||||
// amount.
|
||||
// If current Timestamp instance is unset, then no action will
|
||||
// occur. If result value is outside the range of valid Timestamp
|
||||
// values, then Timestamp will be unset.
|
||||
constexpr Timestamp& operator+=(const Duration& duration) {
|
||||
if (!IsSet()) return *this;
|
||||
epoch_milliseconds_ =
|
||||
Normalize(epoch_milliseconds_ + duration.total_milliseconds());
|
||||
return *this;
|
||||
}
|
||||
constexpr Timestamp& operator-=(const Duration& duration) {
|
||||
if (!IsSet()) return *this;
|
||||
epoch_milliseconds_ =
|
||||
Normalize(epoch_milliseconds_ - duration.total_milliseconds());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Timestamp difference.
|
||||
// Returns the duration between the two provided Timestamp
|
||||
// instances.
|
||||
// If either Timestamp instance is unset, then the resulting
|
||||
// Duration is zero.
|
||||
constexpr Duration operator-(const Timestamp& other) const {
|
||||
if (!IsSet() || !other.IsSet()) return Duration();
|
||||
return Duration(epoch_milliseconds_ - other.epoch_milliseconds_);
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr const uint64_t kMinMs = 1;
|
||||
static constexpr const uint64_t kMaxMs = 253402300799999;
|
||||
static constexpr const Milliseconds kMinMsDuration = Milliseconds(kMinMs);
|
||||
static constexpr const Milliseconds kMaxMsDuration = Milliseconds(kMaxMs);
|
||||
static constexpr const Milliseconds kUnsetMsDuration = Milliseconds::zero();
|
||||
|
||||
static constexpr bool IsInRange(const Milliseconds& epoch_milliseconds) {
|
||||
return epoch_milliseconds >= kMinMsDuration &&
|
||||
epoch_milliseconds <= kMaxMsDuration;
|
||||
}
|
||||
|
||||
// Ensures the provided |epoch_milliseconds| is in range of the
|
||||
// Timestamp class; otherwise returns an unset duration value.
|
||||
static constexpr Milliseconds Normalize(
|
||||
const Milliseconds& epoch_milliseconds) {
|
||||
return IsInRange(epoch_milliseconds) ? epoch_milliseconds
|
||||
: kUnsetMsDuration;
|
||||
}
|
||||
|
||||
constexpr Timestamp(const Milliseconds& epoch_milliseconds)
|
||||
: epoch_milliseconds_(Normalize(epoch_milliseconds)) {}
|
||||
|
||||
Milliseconds epoch_milliseconds_ = kUnsetMsDuration;
|
||||
}; // class Timestamp
|
||||
} // namespace wvutil
|
||||
#endif // WVCDM_UTIL_WV_TIMESTAMP_H_
|
||||
Reference in New Issue
Block a user