| 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 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 88 | 88 |
| 89 template <typename Integer> | 89 template <typename Integer> |
| 90 struct PositionOfSignBit { | 90 struct PositionOfSignBit { |
| 91 static const typename std::enable_if<std::numeric_limits<Integer>::is_integer, | 91 static const typename std::enable_if<std::numeric_limits<Integer>::is_integer, |
| 92 size_t>::type value = | 92 size_t>::type value = |
| 93 CHAR_BIT * sizeof(Integer) - 1; | 93 CHAR_BIT * sizeof(Integer) - 1; |
| 94 }; | 94 }; |
| 95 | 95 |
| 96 // This is used for UnsignedAbs, where we need to support floating-point | 96 // This is used for UnsignedAbs, where we need to support floating-point |
| 97 // template instantiations even though we don't actually support the operations. | 97 // template instantiations even though we don't actually support the operations. |
| 98 // However, there is no corresponding implementation of e.g. CheckedUnsignedAbs, | 98 // However, there is no corresponding implementation of e.g. SafeUnsignedAbs, |
| 99 // so the float versions will not compile. | 99 // so the float versions will not compile. |
| 100 template <typename Numeric, | 100 template <typename Numeric, |
| 101 bool IsInteger = std::numeric_limits<Numeric>::is_integer, | 101 bool IsInteger = std::numeric_limits<Numeric>::is_integer, |
| 102 bool IsFloat = std::numeric_limits<Numeric>::is_iec559> | 102 bool IsFloat = std::numeric_limits<Numeric>::is_iec559> |
| 103 struct UnsignedOrFloatForSize; | 103 struct UnsignedOrFloatForSize; |
| 104 | 104 |
| 105 template <typename Numeric> | 105 template <typename Numeric> |
| 106 struct UnsignedOrFloatForSize<Numeric, true, false> { | 106 struct UnsignedOrFloatForSize<Numeric, true, false> { |
| 107 typedef typename UnsignedIntegerForSize<Numeric>::type type; | 107 typedef typename UnsignedIntegerForSize<Numeric>::type type; |
| 108 }; | 108 }; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 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 // 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, bool>::type |
| 136 CheckedAdd(T x, T y, bool* validity) { | 136 CheckedAdd(T x, T y, T* result) { |
| 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 *result = static_cast<T>(uresult); |
| 143 // Addition is valid if the sign of (x + y) is equal to either that of x or | 144 // Addition is valid if the sign of (x + y) is equal to either that of x or |
| 144 // that of y. | 145 // that of y. |
| 145 if (std::numeric_limits<T>::is_signed) { | 146 return (std::numeric_limits<T>::is_signed) |
| 146 *validity = HasSignBit(BinaryComplement( | 147 ? HasSignBit(BinaryComplement( |
| 147 static_cast<UnsignedDst>((uresult ^ ux) & (uresult ^ uy)))); | 148 static_cast<UnsignedDst>((uresult ^ ux) & (uresult ^ uy)))) |
| 148 } else { // Unsigned is either valid or overflow. | 149 : (BinaryComplement(x) >= |
| 149 *validity = BinaryComplement(x) >= y; | 150 y); // Unsigned is either valid or underflow. |
| 150 } | |
| 151 return static_cast<T>(uresult); | |
| 152 } | 151 } |
| 153 | 152 |
| 154 template <typename T> | 153 template <typename T> |
| 155 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type | 154 typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type |
| 156 CheckedSub(T x, T y, bool* validity) { | 155 CheckedSub(T x, T y, T* result) { |
| 157 // Since the value of x+y is undefined if we have a signed type, we compute | 156 // Since the value of x+y is undefined if we have a signed type, we compute |
| 158 // it using the unsigned type of the same size. | 157 // it using the unsigned type of the same size. |
| 159 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; | 158 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; |
| 160 UnsignedDst ux = static_cast<UnsignedDst>(x); | 159 UnsignedDst ux = static_cast<UnsignedDst>(x); |
| 161 UnsignedDst uy = static_cast<UnsignedDst>(y); | 160 UnsignedDst uy = static_cast<UnsignedDst>(y); |
| 162 UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy); | 161 UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy); |
| 162 *result = static_cast<T>(uresult); |
| 163 // 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 |
| 164 // the same sign. | 164 // the same sign. |
| 165 if (std::numeric_limits<T>::is_signed) { | 165 return (std::numeric_limits<T>::is_signed) |
| 166 *validity = HasSignBit( | 166 ? HasSignBit(BinaryComplement( |
| 167 BinaryComplement(static_cast<UnsignedDst>((uresult ^ ux) & (ux ^ uy)))); | 167 static_cast<UnsignedDst>((uresult ^ ux) & (ux ^ uy)))) |
| 168 } else { // Unsigned is either valid or underflow. | 168 : (x >= y); |
| 169 *validity = x >= y; | |
| 170 } | |
| 171 return static_cast<T>(uresult); | |
| 172 } | 169 } |
| 173 | 170 |
| 174 // Integer multiplication is a bit complicated. In the fast case we just | 171 // Integer multiplication is a bit complicated. In the fast case we just |
| 175 // we just promote to a twice wider type, and range check the result. In the | 172 // we just promote to a twice wider type, and range check the result. In the |
| 176 // slow case we need to manually check that the result won't be truncated by | 173 // slow case we need to manually check that the result won't be truncated by |
| 177 // checking with division against the appropriate bound. | 174 // checking with division against the appropriate bound. |
| 178 template <typename T> | 175 template <typename T> |
| 179 typename std::enable_if<std::numeric_limits<T>::is_integer && | 176 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 180 sizeof(T) * 2 <= sizeof(uintmax_t), | 177 sizeof(T) * 2 <= sizeof(uintmax_t), |
| 181 T>::type | 178 bool>::type |
| 182 CheckedMul(T x, T y, bool* validity) { | 179 CheckedMul(T x, T y, T* result) { |
| 183 typedef typename TwiceWiderInteger<T>::type IntermediateType; | 180 typedef typename TwiceWiderInteger<T>::type IntermediateType; |
| 184 IntermediateType tmp = | 181 IntermediateType tmp = |
| 185 static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); | 182 static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); |
| 186 *validity = DstRangeRelationToSrcRange<T>(tmp) == RANGE_VALID; | 183 *result = static_cast<T>(tmp); |
| 187 return static_cast<T>(tmp); | 184 return DstRangeRelationToSrcRange<T>(tmp) == RANGE_VALID; |
| 188 } | 185 } |
| 189 | 186 |
| 190 template <typename T> | 187 template <typename T> |
| 191 typename std::enable_if<std::numeric_limits<T>::is_integer && | 188 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 192 std::numeric_limits<T>::is_signed && | 189 std::numeric_limits<T>::is_signed && |
| 193 (sizeof(T) * 2 > sizeof(uintmax_t)), | 190 (sizeof(T) * 2 > sizeof(uintmax_t)), |
| 194 T>::type | 191 bool>::type |
| 195 CheckedMul(T x, T y, bool* validity) { | 192 CheckedMul(T x, T y, T* result) { |
| 196 // If either side is zero then the result will be zero. | 193 if (x && y) { |
| 197 if (!x || !y) { | 194 if (x > 0) { |
| 198 *validity = true; | 195 if (y > 0) { |
| 199 return static_cast<T>(0); | 196 if (x > std::numeric_limits<T>::max() / y) |
| 200 } | 197 return false; |
| 201 if (x > 0) { | 198 } else { |
| 202 if (y > 0) { | 199 if (y < std::numeric_limits<T>::min() / x) |
| 203 *validity = x <= std::numeric_limits<T>::max() / y; | 200 return false; |
| 201 } |
| 204 } else { | 202 } else { |
| 205 *validity = y >= std::numeric_limits<T>::min() / x; | 203 if (y > 0) { |
| 206 } | 204 if (x < std::numeric_limits<T>::min() / y) |
| 207 } else { | 205 return false; |
| 208 if (y > 0) { | 206 } else { |
| 209 *validity = x >= std::numeric_limits<T>::min() / y; | 207 if (y < std::numeric_limits<T>::max() / x) |
| 210 } else { | 208 return false; |
| 211 *validity = y >= std::numeric_limits<T>::max() / x; | 209 } |
| 212 } | 210 } |
| 213 } | 211 } |
| 214 return static_cast<T>(*validity ? x * y : 0); | 212 *result = x * y; |
| 213 return true; |
| 215 } | 214 } |
| 216 | 215 |
| 217 template <typename T> | 216 template <typename T> |
| 218 typename std::enable_if<std::numeric_limits<T>::is_integer && | 217 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 219 !std::numeric_limits<T>::is_signed && | 218 !std::numeric_limits<T>::is_signed && |
| 220 (sizeof(T) * 2 > sizeof(uintmax_t)), | 219 (sizeof(T) * 2 > sizeof(uintmax_t)), |
| 221 T>::type | 220 bool>::type |
| 222 CheckedMul(T x, T y, bool* validity) { | 221 CheckedMul(T x, T y, T* result) { |
| 223 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y); | 222 *result = x * y; |
| 224 return static_cast<T>(*validity ? x * y : 0); | 223 return (y == 0 || x <= std::numeric_limits<T>::max() / y); |
| 225 } | 224 } |
| 226 | 225 |
| 227 // Division just requires a check for a zero denominator or an invalid negation | 226 // Division just requires a check for a zero denominator or an invalid negation |
| 228 // on signed min/-1. | 227 // on signed min/-1. |
| 229 template <typename T> | 228 template <typename T> |
| 230 T CheckedDiv(T x, | 229 typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type |
| 231 T y, | 230 CheckedDiv(T x, T y, T* result) { |
| 232 bool* validity, | 231 if (y && (!std::numeric_limits<T>::is_signed || |
| 233 typename std::enable_if<std::numeric_limits<T>::is_integer, | 232 x != std::numeric_limits<T>::min() || y != static_cast<T>(-1))) { |
| 234 int>::type = 0) { | 233 *result = x / y; |
| 235 if ((y == 0) || | 234 return true; |
| 236 (std::numeric_limits<T>::is_signed && | |
| 237 x == std::numeric_limits<T>::min() && y == static_cast<T>(-1))) { | |
| 238 *validity = false; | |
| 239 return static_cast<T>(0); | |
| 240 } | 235 } |
| 241 | 236 return false; |
| 242 *validity = true; | |
| 243 return static_cast<T>(x / y); | |
| 244 } | 237 } |
| 245 | 238 |
| 246 template <typename T> | 239 template <typename T> |
| 247 typename std::enable_if<std::numeric_limits<T>::is_integer && | 240 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 248 std::numeric_limits<T>::is_signed, | 241 std::numeric_limits<T>::is_signed, |
| 249 T>::type | 242 bool>::type |
| 250 CheckedMod(T x, T y, bool* validity) { | 243 CheckedMod(T x, T y, T* result) { |
| 251 *validity = y > 0; | 244 if (y > 0) { |
| 252 return static_cast<T>(*validity ? x % y : 0); | 245 *result = static_cast<T>(x % y); |
| 246 return true; |
| 247 } |
| 248 return false; |
| 253 } | 249 } |
| 254 | 250 |
| 255 template <typename T> | 251 template <typename T> |
| 256 typename std::enable_if<std::numeric_limits<T>::is_integer && | 252 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 257 !std::numeric_limits<T>::is_signed, | 253 !std::numeric_limits<T>::is_signed, |
| 258 T>::type | 254 bool>::type |
| 259 CheckedMod(T x, T y, bool* validity) { | 255 CheckedMod(T x, T y, T* result) { |
| 260 *validity = y != 0; | 256 if (y != 0) { |
| 261 return static_cast<T>(*validity ? x % y : 0); | 257 *result = static_cast<T>(x % y); |
| 258 return true; |
| 259 } |
| 260 return false; |
| 262 } | 261 } |
| 263 | 262 |
| 264 template <typename T> | 263 template <typename T> |
| 265 typename std::enable_if<std::numeric_limits<T>::is_integer && | 264 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 266 std::numeric_limits<T>::is_signed, | 265 std::numeric_limits<T>::is_signed, |
| 267 T>::type | 266 bool>::type |
| 268 CheckedNeg(T value, bool* validity) { | 267 CheckedNeg(T value, T* result) { |
| 269 *validity = value != std::numeric_limits<T>::min(); | |
| 270 // The negation of signed min is min, so catch that one. | 268 // The negation of signed min is min, so catch that one. |
| 271 return static_cast<T>(*validity ? -value : 0); | 269 if (value != std::numeric_limits<T>::min()) { |
| 270 *result = static_cast<T>(-value); |
| 271 return true; |
| 272 } |
| 273 return false; |
| 272 } | 274 } |
| 273 | 275 |
| 274 template <typename T> | 276 template <typename T> |
| 275 typename std::enable_if<std::numeric_limits<T>::is_integer && | 277 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 276 !std::numeric_limits<T>::is_signed, | 278 !std::numeric_limits<T>::is_signed, |
| 277 T>::type | 279 bool>::type |
| 278 CheckedNeg(T value, bool* validity) { | 280 CheckedNeg(T value, T* result) { |
| 279 // The only legal unsigned negation is zero. | 281 if (!value) { // The only legal unsigned negation is zero. |
| 280 *validity = !value; | 282 *result = static_cast<T>(0); |
| 281 return static_cast<T>( | 283 return true; |
| 282 *validity ? -static_cast<typename SignedIntegerForSize<T>::type>(value) | 284 } |
| 283 : 0); | 285 return false; |
| 284 } | 286 } |
| 285 | 287 |
| 286 template <typename T> | 288 template <typename T> |
| 287 typename std::enable_if<std::numeric_limits<T>::is_integer && | 289 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 288 std::numeric_limits<T>::is_signed, | 290 std::numeric_limits<T>::is_signed, |
| 289 T>::type | 291 bool>::type |
| 290 CheckedAbs(T value, bool* validity) { | 292 CheckedAbs(T value, T* result) { |
| 291 *validity = value != std::numeric_limits<T>::min(); | 293 if (value != std::numeric_limits<T>::min()) { |
| 292 return static_cast<T>(*validity ? std::abs(value) : 0); | 294 *result = std::abs(value); |
| 295 return true; |
| 296 } |
| 297 return false; |
| 293 } | 298 } |
| 294 | 299 |
| 295 template <typename T> | 300 template <typename T> |
| 296 typename std::enable_if<std::numeric_limits<T>::is_integer && | 301 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 297 !std::numeric_limits<T>::is_signed, | 302 !std::numeric_limits<T>::is_signed, |
| 298 T>::type | 303 bool>::type |
| 299 CheckedAbs(T value, bool* validity) { | 304 CheckedAbs(T value, T* result) { |
| 300 // T is unsigned, so |value| must already be positive. | 305 // T is unsigned, so |value| must already be positive. |
| 301 *validity = true; | 306 *result = value; |
| 302 return value; | 307 return true; |
| 303 } | 308 } |
| 304 | 309 |
| 305 template <typename T> | 310 template <typename T> |
| 306 typename std::enable_if<std::numeric_limits<T>::is_integer && | 311 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 307 std::numeric_limits<T>::is_signed, | 312 std::numeric_limits<T>::is_signed, |
| 308 typename UnsignedIntegerForSize<T>::type>::type | 313 typename UnsignedIntegerForSize<T>::type>::type |
| 309 CheckedUnsignedAbs(T value) { | 314 SafeUnsignedAbs(T value) { |
| 310 typedef typename UnsignedIntegerForSize<T>::type UnsignedT; | 315 typedef typename UnsignedIntegerForSize<T>::type UnsignedT; |
| 311 return value == std::numeric_limits<T>::min() | 316 return value == std::numeric_limits<T>::min() |
| 312 ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1 | 317 ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1 |
| 313 : static_cast<UnsignedT>(std::abs(value)); | 318 : static_cast<UnsignedT>(std::abs(value)); |
| 314 } | 319 } |
| 315 | 320 |
| 316 template <typename T> | 321 template <typename T> |
| 317 typename std::enable_if<std::numeric_limits<T>::is_integer && | 322 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 318 !std::numeric_limits<T>::is_signed, | 323 !std::numeric_limits<T>::is_signed, |
| 319 T>::type | 324 T>::type |
| 320 CheckedUnsignedAbs(T value) { | 325 SafeUnsignedAbs(T value) { |
| 321 // T is unsigned, so |value| must already be positive. | 326 // T is unsigned, so |value| must already be positive. |
| 322 return static_cast<T>(value); | 327 return static_cast<T>(value); |
| 323 } | 328 } |
| 324 | 329 |
| 325 // These are the floating point stubs that the compiler needs to see. Only the | 330 template <typename T> |
| 326 // negation operation is ever called. | 331 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg( |
| 327 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ | 332 T value, |
| 328 template <typename T> \ | 333 bool*) { |
| 329 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \ | 334 NOTREACHED(); |
| 330 Checked##NAME(T, T, bool*) { \ | 335 return static_cast<T>(-value); |
| 331 NOTREACHED(); \ | 336 } |
| 332 return static_cast<T>(0); \ | 337 |
| 338 template <typename T> |
| 339 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs( |
| 340 T value, |
| 341 bool*) { |
| 342 NOTREACHED(); |
| 343 return static_cast<T>(std::abs(value)); |
| 344 } |
| 345 |
| 346 // These are the floating point stubs that the compiler needs to see. |
| 347 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ |
| 348 template <typename T> \ |
| 349 typename std::enable_if<std::numeric_limits<T>::is_iec559, bool>::type \ |
| 350 Checked##NAME(T, T, T*) { \ |
| 351 NOTREACHED(); \ |
| 352 return static_cast<T>(false); \ |
| 333 } | 353 } |
| 334 | 354 |
| 335 BASE_FLOAT_ARITHMETIC_STUBS(Add) | 355 BASE_FLOAT_ARITHMETIC_STUBS(Add) |
| 336 BASE_FLOAT_ARITHMETIC_STUBS(Sub) | 356 BASE_FLOAT_ARITHMETIC_STUBS(Sub) |
| 337 BASE_FLOAT_ARITHMETIC_STUBS(Mul) | 357 BASE_FLOAT_ARITHMETIC_STUBS(Mul) |
| 338 BASE_FLOAT_ARITHMETIC_STUBS(Div) | 358 BASE_FLOAT_ARITHMETIC_STUBS(Div) |
| 339 BASE_FLOAT_ARITHMETIC_STUBS(Mod) | 359 BASE_FLOAT_ARITHMETIC_STUBS(Mod) |
| 340 | 360 |
| 341 #undef BASE_FLOAT_ARITHMETIC_STUBS | 361 #undef BASE_FLOAT_ARITHMETIC_STUBS |
| 342 | 362 |
| 343 template <typename T> | 363 template <typename T> |
| 344 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg( | 364 typename std::enable_if<std::numeric_limits<T>::is_iec559, bool>::type |
| 345 T value, | 365 CheckedNeg(T value, T* result) { |
| 346 bool*) { | 366 *result = static_cast<T>(-value); |
| 347 return static_cast<T>(-value); | 367 return true; |
| 348 } | 368 } |
| 349 | 369 |
| 350 template <typename T> | 370 template <typename T> |
| 351 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs( | 371 typename std::enable_if<std::numeric_limits<T>::is_iec559, bool>::type |
| 352 T value, | 372 CheckedAbs(T value, T* result) { |
| 353 bool*) { | 373 *result = static_cast<T>(std::abs(value)); |
| 354 return static_cast<T>(std::abs(value)); | 374 return true; |
| 355 } | 375 } |
| 356 | 376 |
| 357 // Floats carry around their validity state with them, but integers do not. So, | 377 // Floats carry around their validity state with them, but integers do not. So, |
| 358 // we wrap the underlying value in a specialization in order to hide that detail | 378 // we wrap the underlying value in a specialization in order to hide that detail |
| 359 // and expose an interface via accessors. | 379 // and expose an interface via accessors. |
| 360 enum NumericRepresentation { | 380 enum NumericRepresentation { |
| 361 NUMERIC_INTEGER, | 381 NUMERIC_INTEGER, |
| 362 NUMERIC_FLOATING, | 382 NUMERIC_FLOATING, |
| 363 NUMERIC_UNKNOWN | 383 NUMERIC_UNKNOWN |
| 364 }; | 384 }; |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 488 sizeof(T) >= (2 * sizeof(Lhs)) && | 508 sizeof(T) >= (2 * sizeof(Lhs)) && |
| 489 StaticDstRangeRelationToSrcRange<T, Rhs>::value != | 509 StaticDstRangeRelationToSrcRange<T, Rhs>::value != |
| 490 NUMERIC_RANGE_CONTAINED && | 510 NUMERIC_RANGE_CONTAINED && |
| 491 sizeof(T) >= (2 * sizeof(Rhs)); | 511 sizeof(T) >= (2 * sizeof(Rhs)); |
| 492 }; | 512 }; |
| 493 | 513 |
| 494 } // namespace internal | 514 } // namespace internal |
| 495 } // namespace base | 515 } // namespace base |
| 496 | 516 |
| 497 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ | 517 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
| OLD | NEW |