Advertisement
Guest User

Untitled

a guest
Aug 20th, 2019
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.76 KB | None | 0 0
  1. // UnitBase is a base class for implementing custom value types with a specific
  2. // unit. It provides type safety and commonly useful operations. The underlying
  3. // storage is always an int64_t, it's up to the unit implementation to choose
  4. // what scale it represents.
  5. //
  6. // It's used like:
  7. // class MyUnit: public UnitBase<MyUnit> {...};
  8. //
  9. // Unit_T is the subclass representing the specific unit.
  10. template <class Unit_T>
  11. class UnitBase {
  12.  public:
  13.   UnitBase() = delete;
  14.   static constexpr Unit_T Zero() { return Unit_T(0); }
  15.   static constexpr Unit_T PlusInfinity() { return Unit_T(PlusInfinityVal()); }
  16.   static constexpr Unit_T MinusInfinity() { return Unit_T(MinusInfinityVal()); }
  17.  
  18.   constexpr bool IsZero() const { return value_ == 0; }
  19.   constexpr bool IsFinite() const { return !IsInfinite(); }
  20.   constexpr bool IsInfinite() const {
  21.     return value_ == PlusInfinityVal() || value_ == MinusInfinityVal();
  22.   }
  23.   constexpr bool IsPlusInfinity() const { return value_ == PlusInfinityVal(); }
  24.   constexpr bool IsMinusInfinity() const {
  25.     return value_ == MinusInfinityVal();
  26.   }
  27.  
  28.   constexpr bool operator==(const Unit_T& other) const {
  29.     return value_ == other.value_;
  30.   }
  31.   constexpr bool operator!=(const Unit_T& other) const {
  32.     return value_ != other.value_;
  33.   }
  34.   constexpr bool operator<=(const Unit_T& other) const {
  35.     return value_ <= other.value_;
  36.   }
  37.   constexpr bool operator>=(const Unit_T& other) const {
  38.     return value_ >= other.value_;
  39.   }
  40.   constexpr bool operator>(const Unit_T& other) const {
  41.     return value_ > other.value_;
  42.   }
  43.   constexpr bool operator<(const Unit_T& other) const {
  44.     return value_ < other.value_;
  45.   }
  46.  
  47.  protected:
  48.   template <int64_t value>
  49.   static constexpr Unit_T FromStaticValue() {
  50.     static_assert(value >= 0 || !Unit_T::one_sided, "");
  51.     static_assert(value > MinusInfinityVal(), "");
  52.     static_assert(value < PlusInfinityVal(), "");
  53.     return Unit_T(value);
  54.   }
  55.  
  56.   template <int64_t fraction_value, int64_t Denominator>
  57.   static constexpr Unit_T FromStaticFraction() {
  58.     static_assert(fraction_value >= 0 || !Unit_T::one_sided, "");
  59.     static_assert(fraction_value > MinusInfinityVal() / Denominator, "");
  60.     static_assert(fraction_value < PlusInfinityVal() / Denominator, "");
  61.     return Unit_T(fraction_value * Denominator);
  62.   }
  63.  
  64.   template <
  65.       typename T,
  66.       typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
  67.   static Unit_T FromValue(T value) {
  68.     if (Unit_T::one_sided)
  69.       RTC_DCHECK_GE(value, 0);
  70.     RTC_DCHECK_GT(value, MinusInfinityVal());
  71.     RTC_DCHECK_LT(value, PlusInfinityVal());
  72.     return Unit_T(rtc::dchecked_cast<int64_t>(value));
  73.   }
  74.   template <typename T,
  75.             typename std::enable_if<std::is_floating_point<T>::value>::type* =
  76.                 nullptr>
  77.   static Unit_T FromValue(T value) {
  78.     if (value == std::numeric_limits<T>::infinity()) {
  79.       return PlusInfinity();
  80.     } else if (value == -std::numeric_limits<T>::infinity()) {
  81.       return MinusInfinity();
  82.     } else {
  83.       RTC_DCHECK(!std::isnan(value));
  84.       return FromValue(rtc::dchecked_cast<int64_t>(value));
  85.     }
  86.   }
  87.  
  88.   template <
  89.       int64_t Denominator,
  90.       typename T,
  91.       typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
  92.   static Unit_T FromFraction(T value) {
  93.     if (Unit_T::one_sided)
  94.       RTC_DCHECK_GE(value, 0);
  95.     RTC_DCHECK_GT(value, MinusInfinityVal() / Denominator);
  96.     RTC_DCHECK_LT(value, PlusInfinityVal() / Denominator);
  97.     return Unit_T(rtc::dchecked_cast<int64_t>(value * Denominator));
  98.   }
  99.   template <int64_t Denominator,
  100.             typename T,
  101.             typename std::enable_if<std::is_floating_point<T>::value>::type* =
  102.                 nullptr>
  103.   static Unit_T FromFraction(T value) {
  104.     return FromValue(value * Denominator);
  105.   }
  106.  
  107.   template <typename T = int64_t>
  108.   typename std::enable_if<std::is_integral<T>::value, T>::type ToValue() const {
  109.     RTC_DCHECK(IsFinite());
  110.     return rtc::dchecked_cast<T>(value_);
  111.   }
  112.   template <typename T>
  113.   constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
  114.   ToValue() const {
  115.     return IsPlusInfinity()
  116.                ? std::numeric_limits<T>::infinity()
  117.                : IsMinusInfinity() ? -std::numeric_limits<T>::infinity()
  118.                                    : value_;
  119.   }
  120.   template <typename T>
  121.   constexpr T ToValueOr(T fallback_value) const {
  122.     return IsFinite() ? value_ : fallback_value;
  123.   }
  124.  
  125.   template <int64_t Denominator, typename T = int64_t>
  126.   typename std::enable_if<std::is_integral<T>::value, T>::type ToFraction()
  127.       const {
  128.     RTC_DCHECK(IsFinite());
  129.     if (Unit_T::one_sided) {
  130.       return rtc::dchecked_cast<T>(
  131.           DivRoundPositiveToNearest(value_, Denominator));
  132.     } else {
  133.       return rtc::dchecked_cast<T>(DivRoundToNearest(value_, Denominator));
  134.     }
  135.   }
  136.   template <int64_t Denominator, typename T>
  137.   constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
  138.   ToFraction() const {
  139.     return ToValue<T>() * (1 / static_cast<T>(Denominator));
  140.   }
  141.  
  142.   template <int64_t Denominator>
  143.   constexpr int64_t ToFractionOr(int64_t fallback_value) const {
  144.     return IsFinite() ? Unit_T::one_sided
  145.                             ? DivRoundPositiveToNearest(value_, Denominator)
  146.                             : DivRoundToNearest(value_, Denominator)
  147.                       : fallback_value;
  148.   }
  149.  
  150.   template <int64_t Factor, typename T = int64_t>
  151.   typename std::enable_if<std::is_integral<T>::value, T>::type ToMultiple()
  152.       const {
  153.     RTC_DCHECK_GE(ToValue(), std::numeric_limits<T>::min() / Factor);
  154.     RTC_DCHECK_LE(ToValue(), std::numeric_limits<T>::max() / Factor);
  155.     return rtc::dchecked_cast<T>(ToValue() * Factor);
  156.   }
  157.   template <int64_t Factor, typename T>
  158.   constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
  159.   ToMultiple() const {
  160.     return ToValue<T>() * Factor;
  161.   }
  162.  
  163.   explicit constexpr UnitBase(int64_t value) : value_(value) {}
  164.  
  165.  private:
  166.   template <class RelativeUnit_T>
  167.   friend class RelativeUnit;
  168.  
  169.   static inline constexpr int64_t PlusInfinityVal() {
  170.     return std::numeric_limits<int64_t>::max();
  171.   }
  172.   static inline constexpr int64_t MinusInfinityVal() {
  173.     return std::numeric_limits<int64_t>::min();
  174.   }
  175.  
  176.   Unit_T& AsSubClassRef() { return reinterpret_cast<Unit_T&>(*this); }
  177.   constexpr const Unit_T& AsSubClassRef() const {
  178.     return reinterpret_cast<const Unit_T&>(*this);
  179.   }
  180.   // Assumes that n >= 0 and d > 0.
  181.   static constexpr int64_t DivRoundPositiveToNearest(int64_t n, int64_t d) {
  182.     return (n + d / 2) / d;
  183.   }
  184.   // Assumes that d > 0.
  185.   static constexpr int64_t DivRoundToNearest(int64_t n, int64_t d) {
  186.     return (n + (n >= 0 ? d / 2 : -d / 2)) / d;
  187.   }
  188.  
  189.   int64_t value_;
  190. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement