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