| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef BASE_NUMERICS_SAFE_MATH_H_ | 5 #ifndef BASE_NUMERICS_SAFE_MATH_H_ |
| 6 #define BASE_NUMERICS_SAFE_MATH_H_ | 6 #define BASE_NUMERICS_SAFE_MATH_H_ |
| 7 | 7 |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 | 9 |
| 10 #include <limits> | 10 #include <limits> |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 178 template <typename Src> | 178 template <typename Src> |
| 179 static CheckedNumeric<T> cast( | 179 static CheckedNumeric<T> cast( |
| 180 const CheckedNumeric<Src>& u, | 180 const CheckedNumeric<Src>& u, |
| 181 typename std::enable_if<!std::is_same<Src, T>::value, int>::type = 0) { | 181 typename std::enable_if<!std::is_same<Src, T>::value, int>::type = 0) { |
| 182 return u; | 182 return u; |
| 183 } | 183 } |
| 184 | 184 |
| 185 static const CheckedNumeric<T>& cast(const CheckedNumeric<T>& u) { return u; } | 185 static const CheckedNumeric<T>& cast(const CheckedNumeric<T>& u) { return u; } |
| 186 | 186 |
| 187 private: | 187 private: |
| 188 template <typename NumericType> | |
| 189 struct UnderlyingType { | |
| 190 using type = NumericType; | |
| 191 }; | |
| 192 | |
| 193 template <typename NumericType> | |
| 194 struct UnderlyingType<CheckedNumeric<NumericType>> { | |
| 195 using type = NumericType; | |
| 196 }; | |
| 197 | |
| 198 CheckedNumericState<T> state_; | 188 CheckedNumericState<T> state_; |
| 199 }; | 189 }; |
| 200 | 190 |
| 201 // This is the boilerplate for the standard arithmetic operator overloads. A | 191 // This is the boilerplate for the standard arithmetic operator overloads. A |
| 202 // macro isn't the prettiest solution, but it beats rewriting these five times. | 192 // macro isn't the prettiest solution, but it beats rewriting these five times. |
| 203 // Some details worth noting are: | 193 // Some details worth noting are: |
| 204 // * We apply the standard arithmetic promotions. | 194 // * We apply the standard arithmetic promotions. |
| 205 // * We skip range checks for floating points. | 195 // * We skip range checks for floating points. |
| 206 // * We skip range checks for destination integers with sufficient range. | 196 // * We skip range checks for destination integers with sufficient range. |
| 207 // TODO(jschuh): extract these out into templates. | 197 // TODO(jschuh): extract these out into templates. |
| 208 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \ | 198 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \ |
| 209 /* Binary arithmetic operator for CheckedNumerics of the same type. */ \ | 199 /* Binary arithmetic operator for CheckedNumerics of the same type. */ \ |
| 210 template <typename T> \ | 200 template <typename L, typename R> \ |
| 211 CheckedNumeric<typename ArithmeticPromotion<T>::type> operator OP( \ | 201 CheckedNumeric<typename ArithmeticPromotion<L, R>::type> operator OP( \ |
| 212 const CheckedNumeric<T>& lhs, const CheckedNumeric<T>& rhs) { \ | 202 const CheckedNumeric<L>& lhs, const CheckedNumeric<R>& rhs) { \ |
| 213 typedef typename ArithmeticPromotion<T>::type Promotion; \ | 203 using P = typename ArithmeticPromotion<L, R>::type; \ |
| 214 /* Floating point always takes the fast path */ \ | 204 if (!rhs.IsValid() || !lhs.IsValid()) \ |
| 215 if (std::numeric_limits<T>::is_iec559) \ | 205 return CheckedNumeric<P>(0, false); \ |
| 216 return CheckedNumeric<T>(lhs.ValueUnsafe() OP rhs.ValueUnsafe()); \ | 206 /* Floating point always takes the fast path */ \ |
| 217 if (!rhs.IsValid() || !lhs.IsValid()) \ | 207 if (std::is_floating_point<L>::value || std::is_floating_point<R>::value) \ |
| 218 return CheckedNumeric<Promotion>(0, false); \ | 208 return CheckedNumeric<P>(lhs.ValueUnsafe() OP rhs.ValueUnsafe()); \ |
| 219 if (IsIntegerArithmeticSafe<Promotion, T, T>::value) \ | 209 P result = 0; \ |
| 220 return CheckedNumeric<Promotion>(lhs.ValueUnsafe() \ | 210 bool is_valid = \ |
| 221 OP rhs.ValueUnsafe()); \ | 211 Checked##NAME(lhs.ValueUnsafe(), rhs.ValueUnsafe(), &result); \ |
| 222 Promotion result = 0; \ | 212 return CheckedNumeric<P>(result, is_valid); \ |
| 223 bool is_valid = \ | 213 } \ |
| 224 Checked##NAME(static_cast<Promotion>(lhs.ValueUnsafe()), \ | 214 /* Assignment arithmetic operator implementation from CheckedNumeric. */ \ |
| 225 static_cast<Promotion>(rhs.ValueUnsafe()), &result); \ | 215 template <typename L> \ |
| 226 return CheckedNumeric<Promotion>(result, is_valid); \ | 216 template <typename R> \ |
| 227 } \ | 217 CheckedNumeric<L>& CheckedNumeric<L>::operator COMPOUND_OP(R rhs) { \ |
| 228 /* Assignment arithmetic operator implementation from CheckedNumeric. */ \ | 218 *this = *this OP rhs; \ |
| 229 template <typename T> \ | 219 return *this; \ |
| 230 template <typename Src> \ | 220 } \ |
| 231 CheckedNumeric<T>& CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) { \ | 221 /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \ |
| 232 *this = CheckedNumeric<T>::cast(*this) \ | 222 template <typename L, typename R, \ |
| 233 OP CheckedNumeric<typename UnderlyingType<Src>::type>::cast(rhs); \ | 223 typename std::enable_if<std::is_arithmetic<R>::value>::type* = \ |
| 234 return *this; \ | 224 nullptr> \ |
| 235 } \ | 225 CheckedNumeric<typename ArithmeticPromotion<L, R>::type> operator OP( \ |
| 236 /* Binary arithmetic operator for CheckedNumeric of different type. */ \ | 226 const CheckedNumeric<L>& lhs, R rhs) { \ |
| 237 template <typename T, typename Src> \ | 227 return lhs OP CheckedNumeric<R>(rhs); \ |
| 238 CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \ | 228 } \ |
| 239 const CheckedNumeric<Src>& lhs, const CheckedNumeric<T>& rhs) { \ | 229 /* Binary arithmetic operator for left numeric and right CheckedNumeric. */ \ |
| 240 typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ | 230 template <typename L, typename R, \ |
| 241 if (!rhs.IsValid() || !lhs.IsValid()) \ | 231 typename std::enable_if<std::is_arithmetic<L>::value>::type* = \ |
| 242 return CheckedNumeric<Promotion>(0, false); \ | 232 nullptr> \ |
| 243 if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ | 233 CheckedNumeric<typename ArithmeticPromotion<L, R>::type> operator OP( \ |
| 244 return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs.ValueUnsafe());\ | 234 L lhs, const CheckedNumeric<R>& rhs) { \ |
| 245 return CheckedNumeric<Promotion>::cast(lhs) \ | 235 return CheckedNumeric<L>(lhs) OP rhs; \ |
| 246 OP CheckedNumeric<Promotion>::cast(rhs); \ | |
| 247 } \ | |
| 248 /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \ | |
| 249 template <typename T, typename Src, \ | |
| 250 typename std::enable_if<std::is_arithmetic<Src>::value>::type* = \ | |
| 251 nullptr> \ | |
| 252 CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \ | |
| 253 const CheckedNumeric<T>& lhs, Src rhs) { \ | |
| 254 typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ | |
| 255 if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ | |
| 256 return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs, \ | |
| 257 lhs.IsValid()); \ | |
| 258 return CheckedNumeric<Promotion>::cast(lhs) \ | |
| 259 OP CheckedNumeric<Promotion>::cast(rhs); \ | |
| 260 } \ | |
| 261 /* Binary arithmetic operator for left numeric and right CheckedNumeric. */ \ | |
| 262 template <typename T, typename Src, \ | |
| 263 typename std::enable_if<std::is_arithmetic<Src>::value>::type* = \ | |
| 264 nullptr> \ | |
| 265 CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \ | |
| 266 Src lhs, const CheckedNumeric<T>& rhs) { \ | |
| 267 typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ | |
| 268 if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ | |
| 269 return CheckedNumeric<Promotion>(lhs OP rhs.ValueUnsafe(), \ | |
| 270 rhs.IsValid()); \ | |
| 271 return CheckedNumeric<Promotion>::cast(lhs) \ | |
| 272 OP CheckedNumeric<Promotion>::cast(rhs); \ | |
| 273 } | 236 } |
| 274 | 237 |
| 275 BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, += ) | 238 BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, += ) |
| 276 BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -= ) | 239 BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -= ) |
| 277 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *= ) | 240 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *= ) |
| 278 BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /= ) | 241 BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /= ) |
| 279 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %= ) | 242 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %= ) |
| 280 | 243 |
| 281 #undef BASE_NUMERIC_ARITHMETIC_OPERATORS | 244 #undef BASE_NUMERIC_ARITHMETIC_OPERATORS |
| 282 | 245 |
| 283 } // namespace internal | 246 } // namespace internal |
| 284 | 247 |
| 285 using internal::CheckedNumeric; | 248 using internal::CheckedNumeric; |
| 286 | 249 |
| 287 } // namespace base | 250 } // namespace base |
| 288 | 251 |
| 289 #endif // BASE_NUMERICS_SAFE_MATH_H_ | 252 #endif // BASE_NUMERICS_SAFE_MATH_H_ |
| OLD | NEW |