| 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 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 // Here are the actual portable checked integer math implementations. | 130 // 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 | 131 // 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. | 132 // way to coalesce things into the CheckedNumericState specializations below. |
| 133 | 133 |
| 134 template <typename T> | 134 template <typename T> |
| 135 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type | 135 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type |
| 136 CheckedAdd(T x, T y, RangeConstraint* validity) { | 136 CheckedAdd(T x, T y, bool* validity) { |
| 137 // Since the value of x+y is undefined if we have a signed type, we compute | 137 // 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. | 138 // it using the unsigned type of the same size. |
| 139 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; | 139 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; |
| 140 UnsignedDst ux = static_cast<UnsignedDst>(x); | 140 UnsignedDst ux = static_cast<UnsignedDst>(x); |
| 141 UnsignedDst uy = static_cast<UnsignedDst>(y); | 141 UnsignedDst uy = static_cast<UnsignedDst>(y); |
| 142 UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy); | 142 UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy); |
| 143 // Addition is valid if the sign of (x + y) is equal to either that of x or | 143 // Addition is valid if the sign of (x + y) is equal to either that of x or |
| 144 // that of y. | 144 // that of y. |
| 145 if (std::numeric_limits<T>::is_signed) { | 145 if (std::numeric_limits<T>::is_signed) { |
| 146 if (HasSignBit(BinaryComplement( | 146 *validity = HasSignBit(BinaryComplement( |
| 147 static_cast<UnsignedDst>((uresult ^ ux) & (uresult ^ uy))))) { | 147 static_cast<UnsignedDst>((uresult ^ ux) & (uresult ^ uy)))); |
| 148 *validity = RANGE_VALID; | |
| 149 } else { // Direction of wrap is inverse of result sign. | |
| 150 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; | |
| 151 } | |
| 152 } else { // Unsigned is either valid or overflow. | 148 } else { // Unsigned is either valid or overflow. |
| 153 *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW; | 149 *validity = BinaryComplement(x) >= y; |
| 154 } | 150 } |
| 155 return static_cast<T>(uresult); | 151 return static_cast<T>(uresult); |
| 156 } | 152 } |
| 157 | 153 |
| 158 template <typename T> | 154 template <typename T> |
| 159 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type | 155 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type |
| 160 CheckedSub(T x, T y, RangeConstraint* validity) { | 156 CheckedSub(T x, T y, bool* validity) { |
| 161 // Since the value of x+y is undefined if we have a signed type, we compute | 157 // Since the value of x+y is undefined if we have a signed type, we compute |
| 162 // it using the unsigned type of the same size. | 158 // it using the unsigned type of the same size. |
| 163 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; | 159 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; |
| 164 UnsignedDst ux = static_cast<UnsignedDst>(x); | 160 UnsignedDst ux = static_cast<UnsignedDst>(x); |
| 165 UnsignedDst uy = static_cast<UnsignedDst>(y); | 161 UnsignedDst uy = static_cast<UnsignedDst>(y); |
| 166 UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy); | 162 UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy); |
| 167 // Subtraction is valid if either x and y have same sign, or (x-y) and x have | 163 // Subtraction is valid if either x and y have same sign, or (x-y) and x have |
| 168 // the same sign. | 164 // the same sign. |
| 169 if (std::numeric_limits<T>::is_signed) { | 165 if (std::numeric_limits<T>::is_signed) { |
| 170 if (HasSignBit(BinaryComplement( | 166 *validity = HasSignBit( |
| 171 static_cast<UnsignedDst>((uresult ^ ux) & (ux ^ uy))))) { | 167 BinaryComplement(static_cast<UnsignedDst>((uresult ^ ux) & (ux ^ uy)))); |
| 172 *validity = RANGE_VALID; | |
| 173 } else { // Direction of wrap is inverse of result sign. | |
| 174 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; | |
| 175 } | |
| 176 } else { // Unsigned is either valid or underflow. | 168 } else { // Unsigned is either valid or underflow. |
| 177 *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW; | 169 *validity = x >= y; |
| 178 } | 170 } |
| 179 return static_cast<T>(uresult); | 171 return static_cast<T>(uresult); |
| 180 } | 172 } |
| 181 | 173 |
| 182 // Integer multiplication is a bit complicated. In the fast case we just | 174 // Integer multiplication is a bit complicated. In the fast case we just |
| 183 // we just promote to a twice wider type, and range check the result. In the | 175 // we just promote to a twice wider type, and range check the result. In the |
| 184 // slow case we need to manually check that the result won't be truncated by | 176 // slow case we need to manually check that the result won't be truncated by |
| 185 // checking with division against the appropriate bound. | 177 // checking with division against the appropriate bound. |
| 186 template <typename T> | 178 template <typename T> |
| 187 typename std::enable_if<std::numeric_limits<T>::is_integer && | 179 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 188 sizeof(T) * 2 <= sizeof(uintmax_t), | 180 sizeof(T) * 2 <= sizeof(uintmax_t), |
| 189 T>::type | 181 T>::type |
| 190 CheckedMul(T x, T y, RangeConstraint* validity) { | 182 CheckedMul(T x, T y, bool* validity) { |
| 191 typedef typename TwiceWiderInteger<T>::type IntermediateType; | 183 typedef typename TwiceWiderInteger<T>::type IntermediateType; |
| 192 IntermediateType tmp = | 184 IntermediateType tmp = |
| 193 static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); | 185 static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); |
| 194 *validity = DstRangeRelationToSrcRange<T>(tmp); | 186 *validity = DstRangeRelationToSrcRange<T>(tmp) == RANGE_VALID; |
| 195 return static_cast<T>(tmp); | 187 return static_cast<T>(tmp); |
| 196 } | 188 } |
| 197 | 189 |
| 198 template <typename T> | 190 template <typename T> |
| 199 typename std::enable_if<std::numeric_limits<T>::is_integer && | 191 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 200 std::numeric_limits<T>::is_signed && | 192 std::numeric_limits<T>::is_signed && |
| 201 (sizeof(T) * 2 > sizeof(uintmax_t)), | 193 (sizeof(T) * 2 > sizeof(uintmax_t)), |
| 202 T>::type | 194 T>::type |
| 203 CheckedMul(T x, T y, RangeConstraint* validity) { | 195 CheckedMul(T x, T y, bool* validity) { |
| 204 // If either side is zero then the result will be zero. | 196 // If either side is zero then the result will be zero. |
| 205 if (!x || !y) { | 197 if (!x || !y) { |
| 206 *validity = RANGE_VALID; | 198 *validity = true; |
| 207 return static_cast<T>(0); | 199 return static_cast<T>(0); |
| 208 } | 200 } |
| 209 if (x > 0) { | 201 if (x > 0) { |
| 210 if (y > 0) { | 202 if (y > 0) { |
| 211 *validity = | 203 *validity = x <= std::numeric_limits<T>::max() / y; |
| 212 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW; | |
| 213 } else { | 204 } else { |
| 214 *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID | 205 *validity = y >= std::numeric_limits<T>::min() / x; |
| 215 : RANGE_UNDERFLOW; | |
| 216 } | 206 } |
| 217 } else { | 207 } else { |
| 218 if (y > 0) { | 208 if (y > 0) { |
| 219 *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID | 209 *validity = x >= std::numeric_limits<T>::min() / y; |
| 220 : RANGE_UNDERFLOW; | |
| 221 } else { | 210 } else { |
| 222 *validity = | 211 *validity = y >= std::numeric_limits<T>::max() / x; |
| 223 y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW; | |
| 224 } | 212 } |
| 225 } | 213 } |
| 226 return static_cast<T>(*validity == RANGE_VALID ? x * y : 0); | 214 return static_cast<T>(*validity ? x * y : 0); |
| 227 } | 215 } |
| 228 | 216 |
| 229 template <typename T> | 217 template <typename T> |
| 230 typename std::enable_if<std::numeric_limits<T>::is_integer && | 218 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 231 !std::numeric_limits<T>::is_signed && | 219 !std::numeric_limits<T>::is_signed && |
| 232 (sizeof(T) * 2 > sizeof(uintmax_t)), | 220 (sizeof(T) * 2 > sizeof(uintmax_t)), |
| 233 T>::type | 221 T>::type |
| 234 CheckedMul(T x, T y, RangeConstraint* validity) { | 222 CheckedMul(T x, T y, bool* validity) { |
| 235 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y) | 223 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y); |
| 236 ? RANGE_VALID | 224 return static_cast<T>(*validity ? x * y : 0); |
| 237 : RANGE_OVERFLOW; | |
| 238 return static_cast<T>(*validity == RANGE_VALID ? x * y : 0); | |
| 239 } | 225 } |
| 240 | 226 |
| 241 // Division just requires a check for a zero denominator or an invalid negation | 227 // Division just requires a check for a zero denominator or an invalid negation |
| 242 // on signed min/-1. | 228 // on signed min/-1. |
| 243 template <typename T> | 229 template <typename T> |
| 244 T CheckedDiv(T x, | 230 T CheckedDiv(T x, |
| 245 T y, | 231 T y, |
| 246 RangeConstraint* validity, | 232 bool* validity, |
| 247 typename std::enable_if<std::numeric_limits<T>::is_integer, | 233 typename std::enable_if<std::numeric_limits<T>::is_integer, |
| 248 int>::type = 0) { | 234 int>::type = 0) { |
| 249 if (y == 0) { | 235 if ((y == 0) || |
| 250 *validity = RANGE_INVALID; | 236 (std::numeric_limits<T>::is_signed && |
| 237 x == std::numeric_limits<T>::min() && y == static_cast<T>(-1))) { |
| 238 *validity = false; |
| 251 return static_cast<T>(0); | 239 return static_cast<T>(0); |
| 252 } | 240 } |
| 253 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() && | |
| 254 y == static_cast<T>(-1)) { | |
| 255 *validity = RANGE_OVERFLOW; | |
| 256 return std::numeric_limits<T>::min(); | |
| 257 } | |
| 258 | 241 |
| 259 *validity = RANGE_VALID; | 242 *validity = true; |
| 260 return static_cast<T>(x / y); | 243 return static_cast<T>(x / y); |
| 261 } | 244 } |
| 262 | 245 |
| 263 template <typename T> | 246 template <typename T> |
| 264 typename std::enable_if<std::numeric_limits<T>::is_integer && | 247 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 265 std::numeric_limits<T>::is_signed, | 248 std::numeric_limits<T>::is_signed, |
| 266 T>::type | 249 T>::type |
| 267 CheckedMod(T x, T y, RangeConstraint* validity) { | 250 CheckedMod(T x, T y, bool* validity) { |
| 268 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; | 251 *validity = y > 0; |
| 269 return static_cast<T>(*validity == RANGE_VALID ? x % y: 0); | 252 return static_cast<T>(*validity ? x % y : 0); |
| 270 } | 253 } |
| 271 | 254 |
| 272 template <typename T> | 255 template <typename T> |
| 273 typename std::enable_if<std::numeric_limits<T>::is_integer && | 256 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 274 !std::numeric_limits<T>::is_signed, | 257 !std::numeric_limits<T>::is_signed, |
| 275 T>::type | 258 T>::type |
| 276 CheckedMod(T x, T y, RangeConstraint* validity) { | 259 CheckedMod(T x, T y, bool* validity) { |
| 277 *validity = y != 0 ? RANGE_VALID : RANGE_INVALID; | 260 *validity = y != 0; |
| 278 return static_cast<T>(*validity == RANGE_VALID ? x % y: 0); | 261 return static_cast<T>(*validity ? x % y : 0); |
| 279 } | 262 } |
| 280 | 263 |
| 281 template <typename T> | 264 template <typename T> |
| 282 typename std::enable_if<std::numeric_limits<T>::is_integer && | 265 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 283 std::numeric_limits<T>::is_signed, | 266 std::numeric_limits<T>::is_signed, |
| 284 T>::type | 267 T>::type |
| 285 CheckedNeg(T value, RangeConstraint* validity) { | 268 CheckedNeg(T value, bool* validity) { |
| 286 *validity = | 269 *validity = value != std::numeric_limits<T>::min(); |
| 287 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; | |
| 288 // The negation of signed min is min, so catch that one. | 270 // The negation of signed min is min, so catch that one. |
| 289 return static_cast<T>(*validity == RANGE_VALID ? -value : 0); | 271 return static_cast<T>(*validity ? -value : 0); |
| 290 } | 272 } |
| 291 | 273 |
| 292 template <typename T> | 274 template <typename T> |
| 293 typename std::enable_if<std::numeric_limits<T>::is_integer && | 275 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 294 !std::numeric_limits<T>::is_signed, | 276 !std::numeric_limits<T>::is_signed, |
| 295 T>::type | 277 T>::type |
| 296 CheckedNeg(T value, RangeConstraint* validity) { | 278 CheckedNeg(T value, bool* validity) { |
| 297 // The only legal unsigned negation is zero. | 279 // The only legal unsigned negation is zero. |
| 298 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; | 280 *validity = !value; |
| 299 return static_cast<T>(*validity == RANGE_VALID ? | 281 return static_cast<T>( |
| 300 -static_cast<typename SignedIntegerForSize<T>::type>(value) : 0); | 282 *validity ? -static_cast<typename SignedIntegerForSize<T>::type>(value) |
| 283 : 0); |
| 301 } | 284 } |
| 302 | 285 |
| 303 template <typename T> | 286 template <typename T> |
| 304 typename std::enable_if<std::numeric_limits<T>::is_integer && | 287 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 305 std::numeric_limits<T>::is_signed, | 288 std::numeric_limits<T>::is_signed, |
| 306 T>::type | 289 T>::type |
| 307 CheckedAbs(T value, RangeConstraint* validity) { | 290 CheckedAbs(T value, bool* validity) { |
| 308 *validity = | 291 *validity = value != std::numeric_limits<T>::min(); |
| 309 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; | 292 return static_cast<T>(*validity ? std::abs(value) : 0); |
| 310 return static_cast<T>(*validity == RANGE_VALID ? std::abs(value) : 0); | |
| 311 } | 293 } |
| 312 | 294 |
| 313 template <typename T> | 295 template <typename T> |
| 314 typename std::enable_if<std::numeric_limits<T>::is_integer && | 296 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 315 !std::numeric_limits<T>::is_signed, | 297 !std::numeric_limits<T>::is_signed, |
| 316 T>::type | 298 T>::type |
| 317 CheckedAbs(T value, RangeConstraint* validity) { | 299 CheckedAbs(T value, bool* validity) { |
| 318 // T is unsigned, so |value| must already be positive. | 300 // T is unsigned, so |value| must already be positive. |
| 319 *validity = RANGE_VALID; | 301 *validity = true; |
| 320 return value; | 302 return value; |
| 321 } | 303 } |
| 322 | 304 |
| 323 template <typename T> | 305 template <typename T> |
| 324 typename std::enable_if<std::numeric_limits<T>::is_integer && | 306 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 325 std::numeric_limits<T>::is_signed, | 307 std::numeric_limits<T>::is_signed, |
| 326 typename UnsignedIntegerForSize<T>::type>::type | 308 typename UnsignedIntegerForSize<T>::type>::type |
| 327 CheckedUnsignedAbs(T value) { | 309 CheckedUnsignedAbs(T value) { |
| 328 typedef typename UnsignedIntegerForSize<T>::type UnsignedT; | 310 typedef typename UnsignedIntegerForSize<T>::type UnsignedT; |
| 329 return value == std::numeric_limits<T>::min() | 311 return value == std::numeric_limits<T>::min() |
| 330 ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1 | 312 ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1 |
| 331 : static_cast<UnsignedT>(std::abs(value)); | 313 : static_cast<UnsignedT>(std::abs(value)); |
| 332 } | 314 } |
| 333 | 315 |
| 334 template <typename T> | 316 template <typename T> |
| 335 typename std::enable_if<std::numeric_limits<T>::is_integer && | 317 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 336 !std::numeric_limits<T>::is_signed, | 318 !std::numeric_limits<T>::is_signed, |
| 337 T>::type | 319 T>::type |
| 338 CheckedUnsignedAbs(T value) { | 320 CheckedUnsignedAbs(T value) { |
| 339 // T is unsigned, so |value| must already be positive. | 321 // T is unsigned, so |value| must already be positive. |
| 340 return static_cast<T>(value); | 322 return static_cast<T>(value); |
| 341 } | 323 } |
| 342 | 324 |
| 343 // These are the floating point stubs that the compiler needs to see. Only the | 325 // These are the floating point stubs that the compiler needs to see. Only the |
| 344 // negation operation is ever called. | 326 // negation operation is ever called. |
| 345 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ | 327 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ |
| 346 template <typename T> \ | 328 template <typename T> \ |
| 347 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \ | 329 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \ |
| 348 Checked##NAME(T, T, RangeConstraint*) { \ | 330 Checked##NAME(T, T, bool*) { \ |
| 349 NOTREACHED(); \ | 331 NOTREACHED(); \ |
| 350 return static_cast<T>(0); \ | 332 return static_cast<T>(0); \ |
| 351 } | 333 } |
| 352 | 334 |
| 353 BASE_FLOAT_ARITHMETIC_STUBS(Add) | 335 BASE_FLOAT_ARITHMETIC_STUBS(Add) |
| 354 BASE_FLOAT_ARITHMETIC_STUBS(Sub) | 336 BASE_FLOAT_ARITHMETIC_STUBS(Sub) |
| 355 BASE_FLOAT_ARITHMETIC_STUBS(Mul) | 337 BASE_FLOAT_ARITHMETIC_STUBS(Mul) |
| 356 BASE_FLOAT_ARITHMETIC_STUBS(Div) | 338 BASE_FLOAT_ARITHMETIC_STUBS(Div) |
| 357 BASE_FLOAT_ARITHMETIC_STUBS(Mod) | 339 BASE_FLOAT_ARITHMETIC_STUBS(Mod) |
| 358 | 340 |
| 359 #undef BASE_FLOAT_ARITHMETIC_STUBS | 341 #undef BASE_FLOAT_ARITHMETIC_STUBS |
| 360 | 342 |
| 361 template <typename T> | 343 template <typename T> |
| 362 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg( | 344 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg( |
| 363 T value, | 345 T value, |
| 364 RangeConstraint*) { | 346 bool*) { |
| 365 return static_cast<T>(-value); | 347 return static_cast<T>(-value); |
| 366 } | 348 } |
| 367 | 349 |
| 368 template <typename T> | 350 template <typename T> |
| 369 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs( | 351 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs( |
| 370 T value, | 352 T value, |
| 371 RangeConstraint*) { | 353 bool*) { |
| 372 return static_cast<T>(std::abs(value)); | 354 return static_cast<T>(std::abs(value)); |
| 373 } | 355 } |
| 374 | 356 |
| 375 // Floats carry around their validity state with them, but integers do not. So, | 357 // Floats carry around their validity state with them, but integers do not. So, |
| 376 // we wrap the underlying value in a specialization in order to hide that detail | 358 // we wrap the underlying value in a specialization in order to hide that detail |
| 377 // and expose an interface via accessors. | 359 // and expose an interface via accessors. |
| 378 enum NumericRepresentation { | 360 enum NumericRepresentation { |
| 379 NUMERIC_INTEGER, | 361 NUMERIC_INTEGER, |
| 380 NUMERIC_FLOATING, | 362 NUMERIC_FLOATING, |
| 381 NUMERIC_UNKNOWN | 363 NUMERIC_UNKNOWN |
| (...skipping 10 matching lines...) Expand all Loading... |
| 392 | 374 |
| 393 template <typename T, NumericRepresentation type = | 375 template <typename T, NumericRepresentation type = |
| 394 GetNumericRepresentation<T>::value> | 376 GetNumericRepresentation<T>::value> |
| 395 class CheckedNumericState {}; | 377 class CheckedNumericState {}; |
| 396 | 378 |
| 397 // Integrals require quite a bit of additional housekeeping to manage state. | 379 // Integrals require quite a bit of additional housekeeping to manage state. |
| 398 template <typename T> | 380 template <typename T> |
| 399 class CheckedNumericState<T, NUMERIC_INTEGER> { | 381 class CheckedNumericState<T, NUMERIC_INTEGER> { |
| 400 private: | 382 private: |
| 401 T value_; | 383 T value_; |
| 402 RangeConstraint validity_ : CHAR_BIT; // Actually requires only two bits. | 384 bool is_valid_; |
| 403 | 385 |
| 404 public: | 386 public: |
| 405 template <typename Src, NumericRepresentation type> | 387 template <typename Src, NumericRepresentation type> |
| 406 friend class CheckedNumericState; | 388 friend class CheckedNumericState; |
| 407 | 389 |
| 408 CheckedNumericState() : value_(0), validity_(RANGE_VALID) {} | 390 CheckedNumericState() : value_(0), is_valid_(true) {} |
| 409 | 391 |
| 410 template <typename Src> | 392 template <typename Src> |
| 411 CheckedNumericState(Src value, RangeConstraint validity) | 393 CheckedNumericState(Src value, bool is_valid) |
| 412 : value_(static_cast<T>(value)), | 394 : value_(static_cast<T>(value)), |
| 413 validity_(GetRangeConstraint(validity | | 395 is_valid_(is_valid && |
| 414 DstRangeRelationToSrcRange<T>(value))) { | 396 (DstRangeRelationToSrcRange<T>(value) == RANGE_VALID)) { |
| 415 static_assert(std::numeric_limits<Src>::is_specialized, | 397 static_assert(std::numeric_limits<Src>::is_specialized, |
| 416 "Argument must be numeric."); | 398 "Argument must be numeric."); |
| 417 } | 399 } |
| 418 | 400 |
| 419 // Copy constructor. | 401 // Copy constructor. |
| 420 template <typename Src> | 402 template <typename Src> |
| 421 CheckedNumericState(const CheckedNumericState<Src>& rhs) | 403 CheckedNumericState(const CheckedNumericState<Src>& rhs) |
| 422 : value_(static_cast<T>(rhs.value())), | 404 : value_(static_cast<T>(rhs.value())), is_valid_(rhs.IsValid()) {} |
| 423 validity_(GetRangeConstraint( | |
| 424 rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {} | |
| 425 | 405 |
| 426 template <typename Src> | 406 template <typename Src> |
| 427 explicit CheckedNumericState( | 407 explicit CheckedNumericState( |
| 428 Src value, | 408 Src value, |
| 429 typename std::enable_if<std::numeric_limits<Src>::is_specialized, | 409 typename std::enable_if<std::numeric_limits<Src>::is_specialized, |
| 430 int>::type = 0) | 410 int>::type = 0) |
| 431 : value_(static_cast<T>(value)), | 411 : value_(static_cast<T>(value)), |
| 432 validity_(DstRangeRelationToSrcRange<T>(value)) {} | 412 is_valid_(DstRangeRelationToSrcRange<T>(value) == RANGE_VALID) {} |
| 433 | 413 |
| 434 RangeConstraint validity() const { return validity_; } | 414 bool is_valid() const { return is_valid_; } |
| 435 T value() const { return value_; } | 415 T value() const { return value_; } |
| 436 }; | 416 }; |
| 437 | 417 |
| 438 // Floating points maintain their own validity, but need translation wrappers. | 418 // Floating points maintain their own validity, but need translation wrappers. |
| 439 template <typename T> | 419 template <typename T> |
| 440 class CheckedNumericState<T, NUMERIC_FLOATING> { | 420 class CheckedNumericState<T, NUMERIC_FLOATING> { |
| 441 private: | 421 private: |
| 442 T value_; | 422 T value_; |
| 443 | 423 |
| 444 public: | 424 public: |
| 445 template <typename Src, NumericRepresentation type> | 425 template <typename Src, NumericRepresentation type> |
| 446 friend class CheckedNumericState; | 426 friend class CheckedNumericState; |
| 447 | 427 |
| 448 CheckedNumericState() : value_(0.0) {} | 428 CheckedNumericState() : value_(0.0) {} |
| 449 | 429 |
| 450 template <typename Src> | 430 template <typename Src> |
| 451 CheckedNumericState( | 431 CheckedNumericState( |
| 452 Src value, | 432 Src value, |
| 453 RangeConstraint validity, | 433 bool is_valid, |
| 454 typename std::enable_if<std::numeric_limits<Src>::is_integer, int>::type = | 434 typename std::enable_if<std::numeric_limits<Src>::is_integer, int>::type = |
| 455 0) { | 435 0) { |
| 456 switch (DstRangeRelationToSrcRange<T>(value)) { | 436 value_ = (is_valid && (DstRangeRelationToSrcRange<T>(value) == RANGE_VALID)) |
| 457 case RANGE_VALID: | 437 ? static_cast<T>(value) |
| 458 value_ = static_cast<T>(value); | 438 : std::numeric_limits<T>::quiet_NaN(); |
| 459 break; | |
| 460 | |
| 461 case RANGE_UNDERFLOW: | |
| 462 value_ = -std::numeric_limits<T>::infinity(); | |
| 463 break; | |
| 464 | |
| 465 case RANGE_OVERFLOW: | |
| 466 value_ = std::numeric_limits<T>::infinity(); | |
| 467 break; | |
| 468 | |
| 469 case RANGE_INVALID: | |
| 470 value_ = std::numeric_limits<T>::quiet_NaN(); | |
| 471 break; | |
| 472 | |
| 473 default: | |
| 474 NOTREACHED(); | |
| 475 } | |
| 476 } | 439 } |
| 477 | 440 |
| 478 template <typename Src> | 441 template <typename Src> |
| 479 explicit CheckedNumericState( | 442 explicit CheckedNumericState( |
| 480 Src value, | 443 Src value, |
| 481 typename std::enable_if<std::numeric_limits<Src>::is_specialized, | 444 typename std::enable_if<std::numeric_limits<Src>::is_specialized, |
| 482 int>::type = 0) | 445 int>::type = 0) |
| 483 : value_(static_cast<T>(value)) {} | 446 : value_(static_cast<T>(value)) {} |
| 484 | 447 |
| 485 // Copy constructor. | 448 // Copy constructor. |
| 486 template <typename Src> | 449 template <typename Src> |
| 487 CheckedNumericState(const CheckedNumericState<Src>& rhs) | 450 CheckedNumericState(const CheckedNumericState<Src>& rhs) |
| 488 : value_(static_cast<T>(rhs.value())) {} | 451 : value_(static_cast<T>(rhs.value())) {} |
| 489 | 452 |
| 490 RangeConstraint validity() const { | 453 bool is_valid() const { return std::isfinite(value_); } |
| 491 return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(), | |
| 492 value_ >= -std::numeric_limits<T>::max()); | |
| 493 } | |
| 494 T value() const { return value_; } | 454 T value() const { return value_; } |
| 495 }; | 455 }; |
| 496 | 456 |
| 497 // For integers less than 128-bit and floats 32-bit or larger, we have the type | 457 // For integers less than 128-bit and floats 32-bit or larger, we have the type |
| 498 // with the larger maximum exponent take precedence. | 458 // with the larger maximum exponent take precedence. |
| 499 enum ArithmeticPromotionCategory { LEFT_PROMOTION, RIGHT_PROMOTION }; | 459 enum ArithmeticPromotionCategory { LEFT_PROMOTION, RIGHT_PROMOTION }; |
| 500 | 460 |
| 501 template <typename Lhs, | 461 template <typename Lhs, |
| 502 typename Rhs = Lhs, | 462 typename Rhs = Lhs, |
| 503 ArithmeticPromotionCategory Promotion = | 463 ArithmeticPromotionCategory Promotion = |
| (...skipping 24 matching lines...) Expand all Loading... |
| 528 sizeof(T) >= (2 * sizeof(Lhs)) && | 488 sizeof(T) >= (2 * sizeof(Lhs)) && |
| 529 StaticDstRangeRelationToSrcRange<T, Rhs>::value != | 489 StaticDstRangeRelationToSrcRange<T, Rhs>::value != |
| 530 NUMERIC_RANGE_CONTAINED && | 490 NUMERIC_RANGE_CONTAINED && |
| 531 sizeof(T) >= (2 * sizeof(Rhs)); | 491 sizeof(T) >= (2 * sizeof(Rhs)); |
| 532 }; | 492 }; |
| 533 | 493 |
| 534 } // namespace internal | 494 } // namespace internal |
| 535 } // namespace base | 495 } // namespace base |
| 536 | 496 |
| 537 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ | 497 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
| OLD | NEW |