blob: ab7b4b25f34ba0f766e013b2ad2bcf17fcd4bac6 [file] [log] [blame]
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef MODULES_CONGESTION_CONTROLLER_NETWORK_CONTROL_INCLUDE_NETWORK_UNITS_H_
#define MODULES_CONGESTION_CONTROLLER_NETWORK_CONTROL_INCLUDE_NETWORK_UNITS_H_
#include <stdint.h>
#include <limits>
#include <ostream>
#include "rtc_base/checks.h"
namespace webrtc {
namespace units_internal {
inline int64_t DivideAndRound(int64_t numerator, int64_t denominators) {
if (numerator >= 0) {
return (numerator + (denominators / 2)) / denominators;
} else {
return (numerator + (denominators / 2)) / denominators - 1;
}
}
} // namespace units_internal
// TimeDelta represents the difference between two timestamps. Connomly this can
// be a duration. However since two Timestamps are not guaranteed to have the
// same epoch (they might come from different computers, making exact
// synchronisation infeasible), the duration covered by a TimeDelta can be
// undefined. To simplify usage, it can be constructed and converted to
// different units, specifically seconds (s), milliseconds (ms) and
// microseconds (us).
class TimeDelta {
public:
static const TimeDelta kPlusInfinity;
static const TimeDelta kMinusInfinity;
static const TimeDelta kNotInitialized;
static const TimeDelta kZero;
TimeDelta() : TimeDelta(kNotInitialized) {}
static TimeDelta Zero() { return kZero; }
static TimeDelta Infinity() { return kPlusInfinity; }
static TimeDelta seconds(int64_t seconds) { return TimeDelta::s(seconds); }
static TimeDelta s(int64_t seconds) {
return TimeDelta::us(seconds * 1000000);
}
static TimeDelta ms(int64_t milliseconds) {
return TimeDelta::us(milliseconds * 1000);
}
static TimeDelta us(int64_t microseconds) {
// Infinities only allowed via use of explicit constants.
RTC_DCHECK(microseconds > std::numeric_limits<int64_t>::min());
RTC_DCHECK(microseconds < std::numeric_limits<int64_t>::max());
return TimeDelta(microseconds);
}
int64_t s() const { return units_internal::DivideAndRound(us(), 1000000); }
int64_t ms() const { return units_internal::DivideAndRound(us(), 1000); }
int64_t us() const {
RTC_DCHECK(IsFinite());
return microseconds_;
}
TimeDelta Abs() const { return TimeDelta::us(std::abs(us())); }
bool IsZero() const { return microseconds_ == 0; }
bool IsFinite() const { return IsInitialized() && !IsInfinite(); }
bool IsInitialized() const {
return microseconds_ != kNotInitialized.microseconds_;
}
bool IsInfinite() const {
return *this == kPlusInfinity || *this == kMinusInfinity;
}
TimeDelta operator+(const TimeDelta& other) const {
return TimeDelta::us(us() + other.us());
}
TimeDelta operator-(const TimeDelta& other) const {
return TimeDelta::us(us() - other.us());
}
TimeDelta operator*(double scalar) const {
return TimeDelta::us(us() * scalar);
}
TimeDelta operator*(int64_t scalar) const {
return TimeDelta::us(us() * scalar);
}
TimeDelta operator*(int32_t scalar) const {
return TimeDelta::us(us() * scalar);
}
bool operator==(const TimeDelta& other) const {
return microseconds_ == other.microseconds_;
}
bool operator!=(const TimeDelta& other) const {
return microseconds_ != other.microseconds_;
}
bool operator<=(const TimeDelta& other) const {
return microseconds_ <= other.microseconds_;
}
bool operator>=(const TimeDelta& other) const {
return microseconds_ >= other.microseconds_;
}
bool operator>(const TimeDelta& other) const {
return microseconds_ > other.microseconds_;
}
bool operator<(const TimeDelta& other) const {
return microseconds_ < other.microseconds_;
}
private:
explicit TimeDelta(int64_t us) : microseconds_(us) {}
int64_t microseconds_;
};
inline TimeDelta operator*(const double& scalar, const TimeDelta& delta) {
return delta * scalar;
}
inline TimeDelta operator*(const int64_t& scalar, const TimeDelta& delta) {
return delta * scalar;
}
inline TimeDelta operator*(const int32_t& scalar, const TimeDelta& delta) {
return delta * scalar;
}
// Timestamp represents the time that has passed since some unspecified epoch.
// The epoch is assumed to be before any represented timestamps, this means that
// negative values are not valid. The most notable feature is that the
// difference of of two Timestamps results in a TimeDelta.
class Timestamp {
public:
static const Timestamp kPlusInfinity;
static const Timestamp kNotInitialized;
Timestamp() : Timestamp(kNotInitialized) {}
static Timestamp Infinity() { return kPlusInfinity; }
static Timestamp s(int64_t seconds) { return Timestamp(seconds * 1000000); }
static Timestamp ms(int64_t millis) { return Timestamp(millis * 1000); }
static Timestamp us(int64_t micros) { return Timestamp(micros); }
int64_t s() const { return units_internal::DivideAndRound(us(), 1000000); }
int64_t ms() const { return units_internal::DivideAndRound(us(), 1000); }
int64_t us() const {
RTC_DCHECK(IsFinite());
return microseconds_;
}
bool IsInfinite() const {
return microseconds_ == kPlusInfinity.microseconds_;
}
bool IsInitialized() const {
return microseconds_ != kNotInitialized.microseconds_;
}
bool IsFinite() const { return IsInitialized() && !IsInfinite(); }
TimeDelta operator-(const Timestamp& other) const {
return TimeDelta::us(us() - other.us());
}
Timestamp operator-(const TimeDelta& delta) const {
return Timestamp::us(us() - delta.us());
}
Timestamp operator+(const TimeDelta& delta) const {
return Timestamp::us(us() + delta.us());
}
bool operator==(const Timestamp& other) const {
return microseconds_ == other.microseconds_;
}
bool operator!=(const Timestamp& other) const {
return microseconds_ != other.microseconds_;
}
bool operator<=(const Timestamp& other) const { return us() <= other.us(); }
bool operator>=(const Timestamp& other) const { return us() >= other.us(); }
bool operator>(const Timestamp& other) const { return us() > other.us(); }
bool operator<(const Timestamp& other) const { return us() < other.us(); }
private:
explicit Timestamp(int64_t us) : microseconds_(us) {}
int64_t microseconds_;
};
// DataSize is a class represeting a count of bytes. Note that while it can be
// initialized by a number of bits, it does not guarantee that the resolution is
// kept and the internal storage is in bytes. The number of bits will be
// truncated to fit.
class DataSize {
public:
static const DataSize kZero;
static const DataSize kPlusInfinity;
static const DataSize kNotInitialized;
DataSize() : DataSize(kNotInitialized) {}
static DataSize Zero() { return kZero; }
static DataSize Infinity() { return kPlusInfinity; }
static DataSize bytes(int64_t bytes) { return DataSize(bytes); }
static DataSize bits(int64_t bits) { return DataSize(bits / 8); }
int64_t bytes() const {
RTC_DCHECK(IsFinite());
return bytes_;
}
int64_t kilobytes() const {
return units_internal::DivideAndRound(bytes(), 1000);
}
int64_t bits() const { return bytes() * 8; }
int64_t kilobits() const {
return units_internal::DivideAndRound(bits(), 1000);
}
bool IsZero() const { return bytes_ == 0; }
bool IsInfinite() const { return bytes_ == kPlusInfinity.bytes_; }
bool IsInitialized() const { return bytes_ != kNotInitialized.bytes_; }
bool IsFinite() const { return IsInitialized() && !IsInfinite(); }
DataSize operator-(const DataSize& other) const {
return DataSize::bytes(bytes() - other.bytes());
}
DataSize operator+(const DataSize& other) const {
return DataSize::bytes(bytes() + other.bytes());
}
DataSize operator*(double scalar) const {
return DataSize::bytes(bytes() * scalar);
}
DataSize operator*(int64_t scalar) const {
return DataSize::bytes(bytes() * scalar);
}
DataSize operator*(int32_t scalar) const {
return DataSize::bytes(bytes() * scalar);
}
DataSize operator/(int64_t scalar) const {
return DataSize::bytes(bytes() / scalar);
}
DataSize& operator-=(const DataSize& other) {
bytes_ -= other.bytes();
return *this;
}
DataSize& operator+=(const DataSize& other) {
bytes_ += other.bytes();
return *this;
}
bool operator==(const DataSize& other) const {
return bytes_ == other.bytes_;
}
bool operator!=(const DataSize& other) const {
return bytes_ != other.bytes_;
}
bool operator<=(const DataSize& other) const {
return bytes_ <= other.bytes_;
}
bool operator>=(const DataSize& other) const {
return bytes_ >= other.bytes_;
}
bool operator>(const DataSize& other) const { return bytes_ > other.bytes_; }
bool operator<(const DataSize& other) const { return bytes_ < other.bytes_; }
private:
explicit DataSize(int64_t bytes) : bytes_(bytes) {}
int64_t bytes_;
};
inline DataSize operator*(const double& scalar, const DataSize& size) {
return size * scalar;
}
inline DataSize operator*(const int64_t& scalar, const DataSize& size) {
return size * scalar;
}
inline DataSize operator*(const int32_t& scalar, const DataSize& size) {
return size * scalar;
}
// DataRate is a class that represents a given data rate. This can be used to
// represent bandwidth, encoding bitrate, etc. The internal storage is currently
// bits per second (bps) since this makes it easier to intepret the raw value
// when debugging. The promised precision, however is only that it will
// represent bytes per second accurately. Any implementation depending on bps
// resolution should document this by changing this comment.
class DataRate {
public:
static const DataRate kZero;
static const DataRate kPlusInfinity;
static const DataRate kNotInitialized;
DataRate() : DataRate(kNotInitialized) {}
static DataRate Zero() { return kZero; }
static DataRate Infinity() { return kPlusInfinity; }
static DataRate bytes_per_second(int64_t bytes_per_sec) {
return DataRate(bytes_per_sec * 8);
}
static DataRate bits_per_second(int64_t bits_per_sec) {
return DataRate(bits_per_sec);
}
static DataRate bps(int64_t bits_per_sec) {
return DataRate::bits_per_second(bits_per_sec);
}
static DataRate kbps(int64_t kilobits_per_sec) {
return DataRate::bits_per_second(kilobits_per_sec * 1000);
}
int64_t bits_per_second() const {
RTC_DCHECK(IsFinite());
return bits_per_sec_;
}
int64_t bytes_per_second() const { return bits_per_second() / 8; }
int64_t bps() const { return bits_per_second(); }
int64_t kbps() const { return units_internal::DivideAndRound(bps(), 1000); }
bool IsZero() const { return bits_per_sec_ == 0; }
bool IsInfinite() const {
return bits_per_sec_ == kPlusInfinity.bits_per_sec_;
}
bool IsInitialized() const {
return bits_per_sec_ != kNotInitialized.bits_per_sec_;
}
bool IsFinite() const { return IsInitialized() && !IsInfinite(); }
DataRate operator*(double scalar) const {
return DataRate::bytes_per_second(bytes_per_second() * scalar);
}
DataRate operator*(int64_t scalar) const {
return DataRate::bytes_per_second(bytes_per_second() * scalar);
}
DataRate operator*(int32_t scalar) const {
return DataRate::bytes_per_second(bytes_per_second() * scalar);
}
bool operator==(const DataRate& other) const {
return bits_per_sec_ == other.bits_per_sec_;
}
bool operator!=(const DataRate& other) const {
return bits_per_sec_ != other.bits_per_sec_;
}
bool operator<=(const DataRate& other) const {
return bits_per_sec_ <= other.bits_per_sec_;
}
bool operator>=(const DataRate& other) const {
return bits_per_sec_ >= other.bits_per_sec_;
}
bool operator>(const DataRate& other) const {
return bits_per_sec_ > other.bits_per_sec_;
}
bool operator<(const DataRate& other) const {
return bits_per_sec_ < other.bits_per_sec_;
}
private:
// Bits per second used internally to simplify debugging by making the value
// more recognizable.
explicit DataRate(int64_t bits_per_second) : bits_per_sec_(bits_per_second) {}
int64_t bits_per_sec_;
};
inline DataRate operator*(const double& scalar, const DataRate& rate) {
return rate * scalar;
}
inline DataRate operator*(const int64_t& scalar, const DataRate& rate) {
return rate * scalar;
}
inline DataRate operator*(const int32_t& scalar, const DataRate& rate) {
return rate * scalar;
}
DataRate operator/(const DataSize& size, const TimeDelta& duration);
TimeDelta operator/(const DataSize& size, const DataRate& rate);
DataSize operator*(const DataRate& rate, const TimeDelta& duration);
DataSize operator*(const TimeDelta& duration, const DataRate& rate);
::std::ostream& operator<<(::std::ostream& os, const DataRate& datarate);
::std::ostream& operator<<(::std::ostream& os, const DataSize& datasize);
::std::ostream& operator<<(::std::ostream& os, const Timestamp& timestamp);
::std::ostream& operator<<(::std::ostream& os, const TimeDelta& delta);
} // namespace webrtc
#endif // MODULES_CONGESTION_CONTROLLER_NETWORK_CONTROL_INCLUDE_NETWORK_UNITS_H_