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