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