clamped_math.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_NUMERICS_CLAMPED_MATH_H_
  5. #define BASE_NUMERICS_CLAMPED_MATH_H_
  6. #include <stddef.h>
  7. #include <limits>
  8. #include <type_traits>
  9. #include "base/numerics/clamped_math_impl.h"
  10. namespace base {
  11. namespace internal {
  12. template <typename T>
  13. class ClampedNumeric {
  14. static_assert(std::is_arithmetic<T>::value,
  15. "ClampedNumeric<T>: T must be a numeric type.");
  16. public:
  17. using type = T;
  18. constexpr ClampedNumeric() : value_(0) {}
  19. // Copy constructor.
  20. template <typename Src>
  21. constexpr ClampedNumeric(const ClampedNumeric<Src>& rhs)
  22. : value_(saturated_cast<T>(rhs.value_)) {}
  23. template <typename Src>
  24. friend class ClampedNumeric;
  25. // This is not an explicit constructor because we implicitly upgrade regular
  26. // numerics to ClampedNumerics to make them easier to use.
  27. template <typename Src>
  28. constexpr ClampedNumeric(Src value) // NOLINT(runtime/explicit)
  29. : value_(saturated_cast<T>(value)) {
  30. static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
  31. }
  32. // This is not an explicit constructor because we want a seamless conversion
  33. // from StrictNumeric types.
  34. template <typename Src>
  35. constexpr ClampedNumeric(
  36. StrictNumeric<Src> value) // NOLINT(runtime/explicit)
  37. : value_(saturated_cast<T>(static_cast<Src>(value))) {}
  38. // Returns a ClampedNumeric of the specified type, cast from the current
  39. // ClampedNumeric, and saturated to the destination type.
  40. template <typename Dst>
  41. constexpr ClampedNumeric<typename UnderlyingType<Dst>::type> Cast() const {
  42. return *this;
  43. }
  44. // Prototypes for the supported arithmetic operator overloads.
  45. template <typename Src>
  46. constexpr ClampedNumeric& operator+=(const Src rhs);
  47. template <typename Src>
  48. constexpr ClampedNumeric& operator-=(const Src rhs);
  49. template <typename Src>
  50. constexpr ClampedNumeric& operator*=(const Src rhs);
  51. template <typename Src>
  52. constexpr ClampedNumeric& operator/=(const Src rhs);
  53. template <typename Src>
  54. constexpr ClampedNumeric& operator%=(const Src rhs);
  55. template <typename Src>
  56. constexpr ClampedNumeric& operator<<=(const Src rhs);
  57. template <typename Src>
  58. constexpr ClampedNumeric& operator>>=(const Src rhs);
  59. template <typename Src>
  60. constexpr ClampedNumeric& operator&=(const Src rhs);
  61. template <typename Src>
  62. constexpr ClampedNumeric& operator|=(const Src rhs);
  63. template <typename Src>
  64. constexpr ClampedNumeric& operator^=(const Src rhs);
  65. constexpr ClampedNumeric operator-() const {
  66. // The negation of two's complement int min is int min, so that's the
  67. // only overflow case where we will saturate.
  68. return ClampedNumeric<T>(SaturatedNegWrapper(value_));
  69. }
  70. constexpr ClampedNumeric operator~() const {
  71. return ClampedNumeric<decltype(InvertWrapper(T()))>(InvertWrapper(value_));
  72. }
  73. constexpr ClampedNumeric Abs() const {
  74. // The negation of two's complement int min is int min, so that's the
  75. // only overflow case where we will saturate.
  76. return ClampedNumeric<T>(SaturatedAbsWrapper(value_));
  77. }
  78. template <typename U>
  79. constexpr ClampedNumeric<typename MathWrapper<ClampedMaxOp, T, U>::type> Max(
  80. const U rhs) const {
  81. using result_type = typename MathWrapper<ClampedMaxOp, T, U>::type;
  82. return ClampedNumeric<result_type>(
  83. ClampedMaxOp<T, U>::Do(value_, Wrapper<U>::value(rhs)));
  84. }
  85. template <typename U>
  86. constexpr ClampedNumeric<typename MathWrapper<ClampedMinOp, T, U>::type> Min(
  87. const U rhs) const {
  88. using result_type = typename MathWrapper<ClampedMinOp, T, U>::type;
  89. return ClampedNumeric<result_type>(
  90. ClampedMinOp<T, U>::Do(value_, Wrapper<U>::value(rhs)));
  91. }
  92. // This function is available only for integral types. It returns an unsigned
  93. // integer of the same width as the source type, containing the absolute value
  94. // of the source, and properly handling signed min.
  95. constexpr ClampedNumeric<typename UnsignedOrFloatForSize<T>::type>
  96. UnsignedAbs() const {
  97. return ClampedNumeric<typename UnsignedOrFloatForSize<T>::type>(
  98. SafeUnsignedAbs(value_));
  99. }
  100. constexpr ClampedNumeric& operator++() {
  101. *this += 1;
  102. return *this;
  103. }
  104. constexpr ClampedNumeric operator++(int) {
  105. ClampedNumeric value = *this;
  106. *this += 1;
  107. return value;
  108. }
  109. constexpr ClampedNumeric& operator--() {
  110. *this -= 1;
  111. return *this;
  112. }
  113. constexpr ClampedNumeric operator--(int) {
  114. ClampedNumeric value = *this;
  115. *this -= 1;
  116. return value;
  117. }
  118. // These perform the actual math operations on the ClampedNumerics.
  119. // Binary arithmetic operations.
  120. template <template <typename, typename, typename> class M,
  121. typename L,
  122. typename R>
  123. static constexpr ClampedNumeric MathOp(const L lhs, const R rhs) {
  124. using Math = typename MathWrapper<M, L, R>::math;
  125. return ClampedNumeric<T>(
  126. Math::template Do<T>(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs)));
  127. }
  128. // Assignment arithmetic operations.
  129. template <template <typename, typename, typename> class M, typename R>
  130. constexpr ClampedNumeric& MathOp(const R rhs) {
  131. using Math = typename MathWrapper<M, T, R>::math;
  132. *this =
  133. ClampedNumeric<T>(Math::template Do<T>(value_, Wrapper<R>::value(rhs)));
  134. return *this;
  135. }
  136. template <typename Dst>
  137. constexpr operator Dst() const {
  138. return saturated_cast<typename ArithmeticOrUnderlyingEnum<Dst>::type>(
  139. value_);
  140. }
  141. // This method extracts the raw integer value without saturating it to the
  142. // destination type as the conversion operator does. This is useful when
  143. // e.g. assigning to an auto type or passing as a deduced template parameter.
  144. constexpr T RawValue() const { return value_; }
  145. private:
  146. T value_;
  147. // These wrappers allow us to handle state the same way for both
  148. // ClampedNumeric and POD arithmetic types.
  149. template <typename Src>
  150. struct Wrapper {
  151. static constexpr Src value(Src value) {
  152. return static_cast<typename UnderlyingType<Src>::type>(value);
  153. }
  154. };
  155. };
  156. // Convience wrapper to return a new ClampedNumeric from the provided arithmetic
  157. // or ClampedNumericType.
  158. template <typename T>
  159. constexpr ClampedNumeric<typename UnderlyingType<T>::type> MakeClampedNum(
  160. const T value) {
  161. return value;
  162. }
  163. #if !BASE_NUMERICS_DISABLE_OSTREAM_OPERATORS
  164. // Overload the ostream output operator to make logging work nicely.
  165. template <typename T>
  166. std::ostream& operator<<(std::ostream& os, const ClampedNumeric<T>& value) {
  167. os << static_cast<T>(value);
  168. return os;
  169. }
  170. #endif
  171. // These implement the variadic wrapper for the math operations.
  172. template <template <typename, typename, typename> class M,
  173. typename L,
  174. typename R>
  175. constexpr ClampedNumeric<typename MathWrapper<M, L, R>::type> ClampMathOp(
  176. const L lhs,
  177. const R rhs) {
  178. using Math = typename MathWrapper<M, L, R>::math;
  179. return ClampedNumeric<typename Math::result_type>::template MathOp<M>(lhs,
  180. rhs);
  181. }
  182. // General purpose wrapper template for arithmetic operations.
  183. template <template <typename, typename, typename> class M,
  184. typename L,
  185. typename R,
  186. typename... Args>
  187. constexpr ClampedNumeric<typename ResultType<M, L, R, Args...>::type>
  188. ClampMathOp(const L lhs, const R rhs, const Args... args) {
  189. return ClampMathOp<M>(ClampMathOp<M>(lhs, rhs), args...);
  190. }
  191. BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Add, +, +=)
  192. BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Sub, -, -=)
  193. BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mul, *, *=)
  194. BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Div, /, /=)
  195. BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mod, %, %=)
  196. BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Lsh, <<, <<=)
  197. BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Rsh, >>, >>=)
  198. BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, And, &, &=)
  199. BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Or, |, |=)
  200. BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Xor, ^, ^=)
  201. BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Max)
  202. BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Min)
  203. BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLess, <)
  204. BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLessOrEqual, <=)
  205. BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreater, >)
  206. BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreaterOrEqual, >=)
  207. BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsEqual, ==)
  208. BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsNotEqual, !=)
  209. } // namespace internal
  210. using internal::ClampedNumeric;
  211. using internal::MakeClampedNum;
  212. using internal::ClampMax;
  213. using internal::ClampMin;
  214. using internal::ClampAdd;
  215. using internal::ClampSub;
  216. using internal::ClampMul;
  217. using internal::ClampDiv;
  218. using internal::ClampMod;
  219. using internal::ClampLsh;
  220. using internal::ClampRsh;
  221. using internal::ClampAnd;
  222. using internal::ClampOr;
  223. using internal::ClampXor;
  224. } // namespace base
  225. #endif // BASE_NUMERICS_CLAMPED_MATH_H_