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