| 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_IMPL_H_ | 5 #ifndef BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
| 6 #define BASE_NUMERICS_SAFE_MATH_IMPL_H_ | 6 #define BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
| 7 | 7 |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 #include <stdint.h> | 9 #include <stdint.h> |
| 10 | 10 |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 120 return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >> | 120 return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >> |
| 121 PositionOfSignBit<T>::value); | 121 PositionOfSignBit<T>::value); |
| 122 } | 122 } |
| 123 | 123 |
| 124 // This wrapper undoes the standard integer promotions. | 124 // This wrapper undoes the standard integer promotions. |
| 125 template <typename T> | 125 template <typename T> |
| 126 constexpr T BinaryComplement(T x) { | 126 constexpr T BinaryComplement(T x) { |
| 127 return static_cast<T>(~x); | 127 return static_cast<T>(~x); |
| 128 } | 128 } |
| 129 | 129 |
| 130 // For integers less than 128-bit and floats 32-bit or larger, we have the type |
| 131 // with the larger maximum exponent take precedence. |
| 132 enum ArithmeticPromotionCategory { LEFT_PROMOTION, RIGHT_PROMOTION }; |
| 133 |
| 134 template <typename Lhs, |
| 135 typename Rhs = Lhs, |
| 136 ArithmeticPromotionCategory Promotion = |
| 137 (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value) |
| 138 ? LEFT_PROMOTION |
| 139 : RIGHT_PROMOTION> |
| 140 struct ArithmeticPromotion; |
| 141 |
| 142 template <typename Lhs, typename Rhs> |
| 143 struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> { |
| 144 typedef Lhs type; |
| 145 }; |
| 146 |
| 147 template <typename Lhs, typename Rhs> |
| 148 struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> { |
| 149 typedef Rhs type; |
| 150 }; |
| 151 |
| 130 // Here are the actual portable checked integer math implementations. | 152 // Here are the actual portable checked integer math implementations. |
| 131 // TODO(jschuh): Break this code out from the enable_if pattern and find a clean | 153 // TODO(jschuh): Break this code out from the enable_if pattern and find a clean |
| 132 // way to coalesce things into the CheckedNumericState specializations below. | 154 // way to coalesce things into the CheckedNumericState specializations below. |
| 133 | 155 |
| 134 template <typename T> | 156 template <typename T> |
| 135 typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type | 157 typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type |
| 136 CheckedAdd(T x, T y, T* result) { | 158 CheckedAddImpl(T x, T y, T* result) { |
| 137 // Since the value of x+y is undefined if we have a signed type, we compute | 159 // Since the value of x+y is undefined if we have a signed type, we compute |
| 138 // it using the unsigned type of the same size. | 160 // it using the unsigned type of the same size. |
| 139 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; | 161 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; |
| 140 UnsignedDst ux = static_cast<UnsignedDst>(x); | 162 UnsignedDst ux = static_cast<UnsignedDst>(x); |
| 141 UnsignedDst uy = static_cast<UnsignedDst>(y); | 163 UnsignedDst uy = static_cast<UnsignedDst>(y); |
| 142 UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy); | 164 UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy); |
| 143 *result = static_cast<T>(uresult); | 165 *result = static_cast<T>(uresult); |
| 144 // Addition is valid if the sign of (x + y) is equal to either that of x or | 166 // Addition is valid if the sign of (x + y) is equal to either that of x or |
| 145 // that of y. | 167 // that of y. |
| 146 return (std::numeric_limits<T>::is_signed) | 168 return (std::numeric_limits<T>::is_signed) |
| 147 ? HasSignBit(BinaryComplement( | 169 ? HasSignBit(BinaryComplement( |
| 148 static_cast<UnsignedDst>((uresult ^ ux) & (uresult ^ uy)))) | 170 static_cast<UnsignedDst>((uresult ^ ux) & (uresult ^ uy)))) |
| 149 : (BinaryComplement(x) >= | 171 : (BinaryComplement(x) >= |
| 150 y); // Unsigned is either valid or underflow. | 172 y); // Unsigned is either valid or underflow. |
| 151 } | 173 } |
| 152 | 174 |
| 175 template <typename T, typename U, typename V> |
| 176 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 177 std::numeric_limits<U>::is_integer && |
| 178 std::numeric_limits<V>::is_integer, |
| 179 bool>::type |
| 180 CheckedAdd(T x, U y, V* result) { |
| 181 using Promotion = typename ArithmeticPromotion<T, U>::type; |
| 182 // Fail if either operand is out of range for the promoted type. |
| 183 // TODO(jschuh): This could be made to work for a broader range of values. |
| 184 if (!IsValueInRangeForNumericType<Promotion>(x) || |
| 185 !IsValueInRangeForNumericType<Promotion>(y)) { |
| 186 return false; |
| 187 } |
| 188 |
| 189 Promotion presult; |
| 190 bool is_valid = CheckedAddImpl(static_cast<Promotion>(x), |
| 191 static_cast<Promotion>(y), &presult); |
| 192 *result = static_cast<V>(presult); |
| 193 return is_valid && IsValueInRangeForNumericType<V>(presult); |
| 194 } |
| 195 |
| 153 template <typename T> | 196 template <typename T> |
| 154 typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type | 197 typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type |
| 155 CheckedSub(T x, T y, T* result) { | 198 CheckedSubImpl(T x, T y, T* result) { |
| 156 // Since the value of x+y is undefined if we have a signed type, we compute | 199 // Since the value of x+y is undefined if we have a signed type, we compute |
| 157 // it using the unsigned type of the same size. | 200 // it using the unsigned type of the same size. |
| 158 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; | 201 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; |
| 159 UnsignedDst ux = static_cast<UnsignedDst>(x); | 202 UnsignedDst ux = static_cast<UnsignedDst>(x); |
| 160 UnsignedDst uy = static_cast<UnsignedDst>(y); | 203 UnsignedDst uy = static_cast<UnsignedDst>(y); |
| 161 UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy); | 204 UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy); |
| 162 *result = static_cast<T>(uresult); | 205 *result = static_cast<T>(uresult); |
| 163 // Subtraction is valid if either x and y have same sign, or (x-y) and x have | 206 // Subtraction is valid if either x and y have same sign, or (x-y) and x have |
| 164 // the same sign. | 207 // the same sign. |
| 165 return (std::numeric_limits<T>::is_signed) | 208 return (std::numeric_limits<T>::is_signed) |
| 166 ? HasSignBit(BinaryComplement( | 209 ? HasSignBit(BinaryComplement( |
| 167 static_cast<UnsignedDst>((uresult ^ ux) & (ux ^ uy)))) | 210 static_cast<UnsignedDst>((uresult ^ ux) & (ux ^ uy)))) |
| 168 : (x >= y); | 211 : (x >= y); |
| 169 } | 212 } |
| 170 | 213 |
| 214 template <typename T, typename U, typename V> |
| 215 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 216 std::numeric_limits<U>::is_integer && |
| 217 std::numeric_limits<V>::is_integer, |
| 218 bool>::type |
| 219 CheckedSub(T x, U y, V* result) { |
| 220 using Promotion = typename ArithmeticPromotion<T, U>::type; |
| 221 // Fail if either operand is out of range for the promoted type. |
| 222 // TODO(jschuh): This could be made to work for a broader range of values. |
| 223 if (!IsValueInRangeForNumericType<Promotion>(x) || |
| 224 !IsValueInRangeForNumericType<Promotion>(y)) { |
| 225 return false; |
| 226 } |
| 227 |
| 228 Promotion presult; |
| 229 bool is_valid = CheckedSubImpl(static_cast<Promotion>(x), |
| 230 static_cast<Promotion>(y), &presult); |
| 231 *result = static_cast<V>(presult); |
| 232 return is_valid && IsValueInRangeForNumericType<V>(presult); |
| 233 } |
| 234 |
| 171 // Integer multiplication is a bit complicated. In the fast case we just | 235 // Integer multiplication is a bit complicated. In the fast case we just |
| 172 // we just promote to a twice wider type, and range check the result. In the | 236 // we just promote to a twice wider type, and range check the result. In the |
| 173 // slow case we need to manually check that the result won't be truncated by | 237 // slow case we need to manually check that the result won't be truncated by |
| 174 // checking with division against the appropriate bound. | 238 // checking with division against the appropriate bound. |
| 175 template <typename T> | 239 template <typename T> |
| 176 typename std::enable_if<std::numeric_limits<T>::is_integer && | 240 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 177 sizeof(T) * 2 <= sizeof(uintmax_t), | 241 sizeof(T) * 2 <= sizeof(uintmax_t), |
| 178 bool>::type | 242 bool>::type |
| 179 CheckedMul(T x, T y, T* result) { | 243 CheckedMulImpl(T x, T y, T* result) { |
| 180 typedef typename TwiceWiderInteger<T>::type IntermediateType; | 244 typedef typename TwiceWiderInteger<T>::type IntermediateType; |
| 181 IntermediateType tmp = | 245 IntermediateType tmp = |
| 182 static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); | 246 static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); |
| 183 *result = static_cast<T>(tmp); | 247 *result = static_cast<T>(tmp); |
| 184 return DstRangeRelationToSrcRange<T>(tmp) == RANGE_VALID; | 248 return DstRangeRelationToSrcRange<T>(tmp) == RANGE_VALID; |
| 185 } | 249 } |
| 186 | 250 |
| 187 template <typename T> | 251 template <typename T> |
| 188 typename std::enable_if<std::numeric_limits<T>::is_integer && | 252 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 189 std::numeric_limits<T>::is_signed && | 253 std::numeric_limits<T>::is_signed && |
| 190 (sizeof(T) * 2 > sizeof(uintmax_t)), | 254 (sizeof(T) * 2 > sizeof(uintmax_t)), |
| 191 bool>::type | 255 bool>::type |
| 192 CheckedMul(T x, T y, T* result) { | 256 CheckedMulImpl(T x, T y, T* result) { |
| 193 if (x && y) { | 257 if (x && y) { |
| 194 if (x > 0) { | 258 if (x > 0) { |
| 195 if (y > 0) { | 259 if (y > 0) { |
| 196 if (x > std::numeric_limits<T>::max() / y) | 260 if (x > std::numeric_limits<T>::max() / y) |
| 197 return false; | 261 return false; |
| 198 } else { | 262 } else { |
| 199 if (y < std::numeric_limits<T>::min() / x) | 263 if (y < std::numeric_limits<T>::min() / x) |
| 200 return false; | 264 return false; |
| 201 } | 265 } |
| 202 } else { | 266 } else { |
| 203 if (y > 0) { | 267 if (y > 0) { |
| 204 if (x < std::numeric_limits<T>::min() / y) | 268 if (x < std::numeric_limits<T>::min() / y) |
| 205 return false; | 269 return false; |
| 206 } else { | 270 } else { |
| 207 if (y < std::numeric_limits<T>::max() / x) | 271 if (y < std::numeric_limits<T>::max() / x) |
| 208 return false; | 272 return false; |
| 209 } | 273 } |
| 210 } | 274 } |
| 211 } | 275 } |
| 212 *result = x * y; | 276 *result = x * y; |
| 213 return true; | 277 return true; |
| 214 } | 278 } |
| 215 | 279 |
| 216 template <typename T> | 280 template <typename T> |
| 217 typename std::enable_if<std::numeric_limits<T>::is_integer && | 281 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 218 !std::numeric_limits<T>::is_signed && | 282 !std::numeric_limits<T>::is_signed && |
| 219 (sizeof(T) * 2 > sizeof(uintmax_t)), | 283 (sizeof(T) * 2 > sizeof(uintmax_t)), |
| 220 bool>::type | 284 bool>::type |
| 221 CheckedMul(T x, T y, T* result) { | 285 CheckedMulImpl(T x, T y, T* result) { |
| 222 *result = x * y; | 286 *result = x * y; |
| 223 return (y == 0 || x <= std::numeric_limits<T>::max() / y); | 287 return (y == 0 || x <= std::numeric_limits<T>::max() / y); |
| 224 } | 288 } |
| 225 | 289 |
| 290 template <typename T, typename U, typename V> |
| 291 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 292 std::numeric_limits<U>::is_integer && |
| 293 std::numeric_limits<V>::is_integer, |
| 294 bool>::type |
| 295 CheckedMul(T x, U y, V* result) { |
| 296 using Promotion = typename ArithmeticPromotion<T, U>::type; |
| 297 // Fail if either operand is out of range for the promoted type. |
| 298 // TODO(jschuh): This could be made to work for a broader range of values. |
| 299 if (!IsValueInRangeForNumericType<Promotion>(x) || |
| 300 !IsValueInRangeForNumericType<Promotion>(y)) { |
| 301 return false; |
| 302 } |
| 303 |
| 304 Promotion presult; |
| 305 bool is_valid = CheckedMulImpl(static_cast<Promotion>(x), |
| 306 static_cast<Promotion>(y), &presult); |
| 307 *result = static_cast<V>(presult); |
| 308 return is_valid && IsValueInRangeForNumericType<V>(presult); |
| 309 } |
| 310 |
| 226 // Division just requires a check for a zero denominator or an invalid negation | 311 // Division just requires a check for a zero denominator or an invalid negation |
| 227 // on signed min/-1. | 312 // on signed min/-1. |
| 228 template <typename T> | 313 template <typename T> |
| 229 typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type | 314 typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type |
| 230 CheckedDiv(T x, T y, T* result) { | 315 CheckedDivImpl(T x, T y, T* result) { |
| 231 if (y && (!std::numeric_limits<T>::is_signed || | 316 if (y && (!std::numeric_limits<T>::is_signed || |
| 232 x != std::numeric_limits<T>::min() || y != static_cast<T>(-1))) { | 317 x != std::numeric_limits<T>::min() || y != static_cast<T>(-1))) { |
| 233 *result = x / y; | 318 *result = x / y; |
| 234 return true; | 319 return true; |
| 235 } | 320 } |
| 236 return false; | 321 return false; |
| 237 } | 322 } |
| 238 | 323 |
| 324 template <typename T, typename U, typename V> |
| 325 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 326 std::numeric_limits<U>::is_integer && |
| 327 std::numeric_limits<V>::is_integer, |
| 328 bool>::type |
| 329 CheckedDiv(T x, U y, V* result) { |
| 330 using Promotion = typename ArithmeticPromotion<T, U>::type; |
| 331 // Fail if either operand is out of range for the promoted type. |
| 332 // TODO(jschuh): This could be made to work for a broader range of values. |
| 333 if (!IsValueInRangeForNumericType<Promotion>(x) || |
| 334 !IsValueInRangeForNumericType<Promotion>(y)) { |
| 335 return false; |
| 336 } |
| 337 |
| 338 Promotion presult; |
| 339 bool is_valid = CheckedDivImpl(static_cast<Promotion>(x), |
| 340 static_cast<Promotion>(y), &presult); |
| 341 *result = static_cast<V>(presult); |
| 342 return is_valid && IsValueInRangeForNumericType<V>(presult); |
| 343 } |
| 344 |
| 239 template <typename T> | 345 template <typename T> |
| 240 typename std::enable_if<std::numeric_limits<T>::is_integer && | 346 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 241 std::numeric_limits<T>::is_signed, | 347 std::numeric_limits<T>::is_signed, |
| 242 bool>::type | 348 bool>::type |
| 243 CheckedMod(T x, T y, T* result) { | 349 CheckedModImpl(T x, T y, T* result) { |
| 244 if (y > 0) { | 350 if (y > 0) { |
| 245 *result = static_cast<T>(x % y); | 351 *result = static_cast<T>(x % y); |
| 246 return true; | 352 return true; |
| 247 } | 353 } |
| 248 return false; | 354 return false; |
| 249 } | 355 } |
| 250 | 356 |
| 251 template <typename T> | 357 template <typename T> |
| 252 typename std::enable_if<std::numeric_limits<T>::is_integer && | 358 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 253 !std::numeric_limits<T>::is_signed, | 359 !std::numeric_limits<T>::is_signed, |
| 254 bool>::type | 360 bool>::type |
| 255 CheckedMod(T x, T y, T* result) { | 361 CheckedModImpl(T x, T y, T* result) { |
| 256 if (y != 0) { | 362 if (y != 0) { |
| 257 *result = static_cast<T>(x % y); | 363 *result = static_cast<T>(x % y); |
| 258 return true; | 364 return true; |
| 259 } | 365 } |
| 260 return false; | 366 return false; |
| 261 } | 367 } |
| 262 | 368 |
| 369 template <typename T, typename U, typename V> |
| 370 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 371 std::numeric_limits<U>::is_integer && |
| 372 std::numeric_limits<V>::is_integer, |
| 373 bool>::type |
| 374 CheckedMod(T x, U y, V* result) { |
| 375 using Promotion = typename ArithmeticPromotion<T, U>::type; |
| 376 Promotion presult; |
| 377 bool is_valid = CheckedModImpl(static_cast<Promotion>(x), |
| 378 static_cast<Promotion>(y), &presult); |
| 379 *result = static_cast<V>(presult); |
| 380 return is_valid && IsValueInRangeForNumericType<V>(presult); |
| 381 } |
| 382 |
| 263 template <typename T> | 383 template <typename T> |
| 264 typename std::enable_if<std::numeric_limits<T>::is_integer && | 384 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 265 std::numeric_limits<T>::is_signed, | 385 std::numeric_limits<T>::is_signed, |
| 266 bool>::type | 386 bool>::type |
| 267 CheckedNeg(T value, T* result) { | 387 CheckedNeg(T value, T* result) { |
| 268 // The negation of signed min is min, so catch that one. | 388 // The negation of signed min is min, so catch that one. |
| 269 if (value != std::numeric_limits<T>::min()) { | 389 if (value != std::numeric_limits<T>::min()) { |
| 270 *result = static_cast<T>(-value); | 390 *result = static_cast<T>(-value); |
| 271 return true; | 391 return true; |
| 272 } | 392 } |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 337 | 457 |
| 338 template <typename T> | 458 template <typename T> |
| 339 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs( | 459 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs( |
| 340 T value, | 460 T value, |
| 341 bool*) { | 461 bool*) { |
| 342 NOTREACHED(); | 462 NOTREACHED(); |
| 343 return static_cast<T>(std::abs(value)); | 463 return static_cast<T>(std::abs(value)); |
| 344 } | 464 } |
| 345 | 465 |
| 346 // These are the floating point stubs that the compiler needs to see. | 466 // These are the floating point stubs that the compiler needs to see. |
| 347 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ | 467 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ |
| 348 template <typename T> \ | 468 template <typename T, typename U, typename V> \ |
| 349 typename std::enable_if<std::numeric_limits<T>::is_iec559, bool>::type \ | 469 typename std::enable_if<std::numeric_limits<T>::is_iec559 || \ |
| 350 Checked##NAME(T, T, T*) { \ | 470 std::numeric_limits<U>::is_iec559 || \ |
| 351 NOTREACHED(); \ | 471 std::numeric_limits<V>::is_iec559, \ |
| 352 return static_cast<T>(false); \ | 472 bool>::type Checked##NAME(T, U, V*) { \ |
| 473 NOTREACHED(); \ |
| 474 return static_cast<T>(false); \ |
| 353 } | 475 } |
| 354 | 476 |
| 355 BASE_FLOAT_ARITHMETIC_STUBS(Add) | 477 BASE_FLOAT_ARITHMETIC_STUBS(Add) |
| 356 BASE_FLOAT_ARITHMETIC_STUBS(Sub) | 478 BASE_FLOAT_ARITHMETIC_STUBS(Sub) |
| 357 BASE_FLOAT_ARITHMETIC_STUBS(Mul) | 479 BASE_FLOAT_ARITHMETIC_STUBS(Mul) |
| 358 BASE_FLOAT_ARITHMETIC_STUBS(Div) | 480 BASE_FLOAT_ARITHMETIC_STUBS(Div) |
| 359 BASE_FLOAT_ARITHMETIC_STUBS(Mod) | 481 BASE_FLOAT_ARITHMETIC_STUBS(Mod) |
| 360 | 482 |
| 361 #undef BASE_FLOAT_ARITHMETIC_STUBS | 483 #undef BASE_FLOAT_ARITHMETIC_STUBS |
| 362 | 484 |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 467 | 589 |
| 468 // Copy constructor. | 590 // Copy constructor. |
| 469 template <typename Src> | 591 template <typename Src> |
| 470 CheckedNumericState(const CheckedNumericState<Src>& rhs) | 592 CheckedNumericState(const CheckedNumericState<Src>& rhs) |
| 471 : value_(static_cast<T>(rhs.value())) {} | 593 : value_(static_cast<T>(rhs.value())) {} |
| 472 | 594 |
| 473 bool is_valid() const { return std::isfinite(value_); } | 595 bool is_valid() const { return std::isfinite(value_); } |
| 474 T value() const { return value_; } | 596 T value() const { return value_; } |
| 475 }; | 597 }; |
| 476 | 598 |
| 477 // For integers less than 128-bit and floats 32-bit or larger, we have the type | |
| 478 // with the larger maximum exponent take precedence. | |
| 479 enum ArithmeticPromotionCategory { LEFT_PROMOTION, RIGHT_PROMOTION }; | |
| 480 | |
| 481 template <typename Lhs, | |
| 482 typename Rhs = Lhs, | |
| 483 ArithmeticPromotionCategory Promotion = | |
| 484 (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value) | |
| 485 ? LEFT_PROMOTION | |
| 486 : RIGHT_PROMOTION> | |
| 487 struct ArithmeticPromotion; | |
| 488 | |
| 489 template <typename Lhs, typename Rhs> | |
| 490 struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> { | |
| 491 typedef Lhs type; | |
| 492 }; | |
| 493 | |
| 494 template <typename Lhs, typename Rhs> | |
| 495 struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> { | |
| 496 typedef Rhs type; | |
| 497 }; | |
| 498 | |
| 499 // We can statically check if operations on the provided types can wrap, so we | |
| 500 // can skip the checked operations if they're not needed. So, for an integer we | |
| 501 // care if the destination type preserves the sign and is twice the width of | |
| 502 // the source. | |
| 503 template <typename T, typename Lhs, typename Rhs> | |
| 504 struct IsIntegerArithmeticSafe { | |
| 505 static const bool value = !std::numeric_limits<T>::is_iec559 && | |
| 506 StaticDstRangeRelationToSrcRange<T, Lhs>::value == | |
| 507 NUMERIC_RANGE_CONTAINED && | |
| 508 sizeof(T) >= (2 * sizeof(Lhs)) && | |
| 509 StaticDstRangeRelationToSrcRange<T, Rhs>::value != | |
| 510 NUMERIC_RANGE_CONTAINED && | |
| 511 sizeof(T) >= (2 * sizeof(Rhs)); | |
| 512 }; | |
| 513 | |
| 514 } // namespace internal | 599 } // namespace internal |
| 515 } // namespace base | 600 } // namespace base |
| 516 | 601 |
| 517 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ | 602 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
| OLD | NEW |