v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
clamped_math.h
Go to the documentation of this file.
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// Slightly adapted for inclusion in V8.
6// Copyright 2025 the V8 project authors. All rights reserved.
7
8#ifndef V8_BASE_NUMERICS_CLAMPED_MATH_H_
9#define V8_BASE_NUMERICS_CLAMPED_MATH_H_
10
11#include <type_traits>
12
13#include "src/base/numerics/clamped_math_impl.h" // IWYU pragma: export
15#include "src/base/numerics/safe_math_shared_impl.h" // IWYU pragma: export
16
17namespace v8::base {
18namespace internal {
19
20template <typename T>
21 requires std::is_arithmetic_v<T>
22class ClampedNumeric {
23 public:
24 using type = T;
25
26 constexpr ClampedNumeric() = default;
27
28 // Copy constructor.
29 template <typename Src>
30 constexpr ClampedNumeric(const ClampedNumeric<Src>& rhs)
31 : value_(saturated_cast<T>(rhs.value_)) {}
32
33 // This is not an explicit constructor because we implicitly upgrade regular
34 // numerics to ClampedNumerics to make them easier to use.
35 template <typename Src>
36 requires(IsNumeric<Src>)
37 // NOLINTNEXTLINE(runtime/explicit)
38 constexpr ClampedNumeric(Src value) : value_(saturated_cast<T>(value)) {}
39
40 // This is not an explicit constructor because we want a seamless conversion
41 // from StrictNumeric types.
42 template <typename Src>
43 // NOLINTNEXTLINE(runtime/explicit)
45 : value_(saturated_cast<T>(static_cast<Src>(value))) {}
46
47 // Returns a ClampedNumeric of the specified type, cast from the current
48 // ClampedNumeric, and saturated to the destination type.
49 template <typename Dst>
51 return *this;
52 }
53
54 // Prototypes for the supported arithmetic operator overloads.
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 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
76 constexpr ClampedNumeric operator-() const {
77 // The negation of two's complement int min is int min, so that's the
78 // only overflow case where we will saturate.
80 }
81
85
86 constexpr ClampedNumeric Abs() 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.
90 }
91
92 template <typename U>
99
100 template <typename U>
107
108 // This function is available only for integral types. It returns an unsigned
109 // integer of the same width as the source type, containing the absolute value
110 // of the source, and properly handling signed min.
116
118 *this += 1;
119 return *this;
120 }
121
122 constexpr ClampedNumeric operator++(int) {
123 ClampedNumeric value = *this;
124 *this += 1;
125 return value;
126 }
127
129 *this -= 1;
130 return *this;
131 }
132
133 constexpr ClampedNumeric operator--(int) {
134 ClampedNumeric value = *this;
135 *this -= 1;
136 return value;
137 }
138
139 // These perform the actual math operations on the ClampedNumerics.
140 // Binary arithmetic operations.
141 template <template <typename, typename> class M, typename L, typename R>
142 static constexpr ClampedNumeric MathOp(L lhs, R rhs) {
143 using Math = typename MathWrapper<M, L, R>::math;
144 return ClampedNumeric<T>(
145 Math::template Do<T>(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs)));
146 }
147
148 // Assignment arithmetic operations.
149 template <template <typename, typename> class M, typename R>
150 constexpr ClampedNumeric& MathOp(R rhs) {
151 using Math = typename MathWrapper<M, T, R>::math;
152 *this =
153 ClampedNumeric<T>(Math::template Do<T>(value_, Wrapper<R>::value(rhs)));
154 return *this;
155 }
156
157 template <typename Dst>
158 requires std::is_arithmetic_v<ArithmeticOrUnderlyingEnum<Dst>>
159 constexpr operator Dst() const { // NOLINT(runtime/explicit)
160 return saturated_cast<ArithmeticOrUnderlyingEnum<Dst>>(value_);
161 }
162
163 // This method extracts the raw integer value without saturating it to the
164 // destination type as the conversion operator does. This is useful when
165 // e.g. assigning to an auto type or passing as a deduced template parameter.
166 constexpr T RawValue() const { return value_; }
167
168 private:
169 template <typename U>
170 requires std::is_arithmetic_v<U>
171 friend class ClampedNumeric;
172
173 T value_ = 0;
174
175 // These wrappers allow us to handle state the same way for both
176 // ClampedNumeric and POD arithmetic types.
177 template <typename Src>
178 struct Wrapper {
179 static constexpr UnderlyingType<Src> value(Src value) { return value; }
180 };
181};
182
183template <typename T>
185
186// Convenience wrapper to return a new ClampedNumeric from the provided
187// arithmetic or ClampedNumericType.
188template <typename T>
190 return value;
191}
192
193// These implement the variadic wrapper for the math operations.
194template <template <typename, typename> class M, typename L, typename R>
196 L lhs, R rhs) {
197 using Math = typename MathWrapper<M, L, R>::math;
199 rhs);
200}
201
202// General purpose wrapper template for arithmetic operations.
203template <template <typename, typename> class M, typename L, typename R,
204 typename... Args>
205constexpr auto ClampMathOp(L lhs, R rhs, Args... args) {
206 return ClampMathOp<M>(ClampMathOp<M>(lhs, rhs), args...);
207}
208
209BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Add, +, +=)
210BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Sub, -, -=)
211BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mul, *, *=)
212BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Div, /, /=)
213BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mod, %, %=)
214BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Lsh, <<, <<=)
215BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Rsh, >>, >>=)
216BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, And, &, &=)
217BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Or, |, |=)
218BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Xor, ^, ^=)
219BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Max)
220BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Min)
221BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLess, <)
222BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLessOrEqual, <=)
223BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreater, >)
224BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreaterOrEqual, >=)
225BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsEqual, ==)
226BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsNotEqual, !=)
227
228} // namespace internal
229
230using internal::ClampAdd;
231using internal::ClampAnd;
232using internal::ClampDiv;
233using internal::ClampedNumeric;
234using internal::ClampLsh;
235using internal::ClampMax;
236using internal::ClampMin;
237using internal::ClampMod;
238using internal::ClampMul;
239using internal::ClampOr;
240using internal::ClampRsh;
241using internal::ClampSub;
242using internal::ClampXor;
243using internal::MakeClampedNum;
244
245} // namespace v8::base
246
247#endif // V8_BASE_NUMERICS_CLAMPED_MATH_H_
#define T
constexpr ClampedNumeric & operator<<=(const Src rhs)
constexpr ClampedNumeric & operator|=(const Src rhs)
constexpr ClampedNumeric & operator/=(const Src rhs)
constexpr ClampedNumeric(StrictNumeric< Src > value)
constexpr ClampedNumeric< UnderlyingType< Dst > > Cast() const
constexpr ClampedNumeric< typename MathWrapper< ClampedMaxOp, T, U >::type > Max(U rhs) const
static constexpr ClampedNumeric MathOp(L lhs, R rhs)
constexpr ClampedNumeric operator~() const
constexpr ClampedNumeric & operator>>=(const Src rhs)
constexpr ClampedNumeric & operator%=(const Src rhs)
constexpr ClampedNumeric & operator-=(const Src rhs)
constexpr ClampedNumeric()=default
constexpr ClampedNumeric Abs() const
constexpr ClampedNumeric & operator&=(const Src rhs)
constexpr ClampedNumeric(Src value)
constexpr ClampedNumeric operator--(int)
constexpr ClampedNumeric< typename UnsignedOrFloatForSize< T >::type > UnsignedAbs() const
constexpr ClampedNumeric & operator++()
constexpr ClampedNumeric< typename MathWrapper< ClampedMinOp, T, U >::type > Min(U rhs) const
constexpr ClampedNumeric operator++(int)
constexpr ClampedNumeric & operator^=(const Src rhs)
constexpr ClampedNumeric operator-() const
constexpr ClampedNumeric & operator+=(const Src rhs)
constexpr ClampedNumeric & MathOp(R rhs)
constexpr ClampedNumeric & operator--()
constexpr ClampedNumeric(const ClampedNumeric< Src > &rhs)
constexpr ClampedNumeric & operator*=(const Src rhs)
constexpr auto SafeUnsignedAbs(T value)
constexpr std::make_unsigned< T >::type InvertWrapper(T value)
UnderlyingTypeImpl< T >::type UnderlyingType
constexpr ClampedNumeric< typename MathWrapper< M, L, R >::type > ClampMathOp(L lhs, R rhs)
constexpr ClampedNumeric< UnderlyingType< T > > MakeClampedNum(T value)
ClampedNumeric(T) -> ClampedNumeric< T >
constexpr T SaturatedAbsWrapper(T value)
constexpr T SaturatedNegWrapper(T value)
V8_BASE_EXPORT int const char va_list args
Definition strings.h:23
#define BASE_NUMERIC_COMPARISON_OPERATORS(CLASS, NAME, OP)
#define BASE_NUMERIC_ARITHMETIC_OPERATORS(CLASS, CL_ABBR, OP_NAME, OP, CMP_OP)
#define BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)
static constexpr UnderlyingType< Src > value(Src value)
std::unique_ptr< ValueMirror > value