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