| 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 <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include <cmath> | 10 #include <cmath> |
| 11 #include <cstdlib> | 11 #include <cstdlib> |
| 12 #include <limits> | 12 #include <limits> |
| 13 #include <type_traits> |
| 13 | 14 |
| 14 #include "base/numerics/safe_conversions.h" | 15 #include "base/numerics/safe_conversions.h" |
| 15 #include "base/template_util.h" | 16 #include "base/template_util.h" |
| 16 | 17 |
| 17 namespace base { | 18 namespace base { |
| 18 namespace internal { | 19 namespace internal { |
| 19 | 20 |
| 20 // Everything from here up to the floating point operations is portable C++, | 21 // Everything from here up to the floating point operations is portable C++, |
| 21 // but it may not be fast. This code could be split based on | 22 // but it may not be fast. This code could be split based on |
| 22 // platform/architecture and replaced with potentially faster implementations. | 23 // platform/architecture and replaced with potentially faster implementations. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 struct IntegerForSizeAndSign<8, false> { | 57 struct IntegerForSizeAndSign<8, false> { |
| 57 typedef uint64_t type; | 58 typedef uint64_t type; |
| 58 }; | 59 }; |
| 59 | 60 |
| 60 // WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to | 61 // WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to |
| 61 // support 128-bit math, then the ArithmeticPromotion template below will need | 62 // support 128-bit math, then the ArithmeticPromotion template below will need |
| 62 // to be updated (or more likely replaced with a decltype expression). | 63 // to be updated (or more likely replaced with a decltype expression). |
| 63 | 64 |
| 64 template <typename Integer> | 65 template <typename Integer> |
| 65 struct UnsignedIntegerForSize { | 66 struct UnsignedIntegerForSize { |
| 66 typedef typename enable_if< | 67 typedef typename std::enable_if< |
| 67 std::numeric_limits<Integer>::is_integer, | 68 std::numeric_limits<Integer>::is_integer, |
| 68 typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type type; | 69 typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type type; |
| 69 }; | 70 }; |
| 70 | 71 |
| 71 template <typename Integer> | 72 template <typename Integer> |
| 72 struct SignedIntegerForSize { | 73 struct SignedIntegerForSize { |
| 73 typedef typename enable_if< | 74 typedef typename std::enable_if< |
| 74 std::numeric_limits<Integer>::is_integer, | 75 std::numeric_limits<Integer>::is_integer, |
| 75 typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type type; | 76 typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type type; |
| 76 }; | 77 }; |
| 77 | 78 |
| 78 template <typename Integer> | 79 template <typename Integer> |
| 79 struct TwiceWiderInteger { | 80 struct TwiceWiderInteger { |
| 80 typedef typename enable_if< | 81 typedef typename std::enable_if< |
| 81 std::numeric_limits<Integer>::is_integer, | 82 std::numeric_limits<Integer>::is_integer, |
| 82 typename IntegerForSizeAndSign< | 83 typename IntegerForSizeAndSign< |
| 83 sizeof(Integer) * 2, | 84 sizeof(Integer) * 2, |
| 84 std::numeric_limits<Integer>::is_signed>::type>::type type; | 85 std::numeric_limits<Integer>::is_signed>::type>::type type; |
| 85 }; | 86 }; |
| 86 | 87 |
| 87 template <typename Integer> | 88 template <typename Integer> |
| 88 struct PositionOfSignBit { | 89 struct PositionOfSignBit { |
| 89 static const typename enable_if<std::numeric_limits<Integer>::is_integer, | 90 static const typename std::enable_if<std::numeric_limits<Integer>::is_integer, |
| 90 size_t>::type value = 8 * sizeof(Integer) - 1; | 91 size_t>::type value = |
| 92 8 * sizeof(Integer) - 1; |
| 91 }; | 93 }; |
| 92 | 94 |
| 93 // This is used for UnsignedAbs, where we need to support floating-point | 95 // This is used for UnsignedAbs, where we need to support floating-point |
| 94 // template instantiations even though we don't actually support the operations. | 96 // template instantiations even though we don't actually support the operations. |
| 95 // However, there is no corresponding implementation of e.g. CheckedUnsignedAbs, | 97 // However, there is no corresponding implementation of e.g. CheckedUnsignedAbs, |
| 96 // so the float versions will not compile. | 98 // so the float versions will not compile. |
| 97 template <typename Numeric, | 99 template <typename Numeric, |
| 98 bool IsInteger = std::numeric_limits<Numeric>::is_integer, | 100 bool IsInteger = std::numeric_limits<Numeric>::is_integer, |
| 99 bool IsFloat = std::numeric_limits<Numeric>::is_iec559> | 101 bool IsFloat = std::numeric_limits<Numeric>::is_iec559> |
| 100 struct UnsignedOrFloatForSize; | 102 struct UnsignedOrFloatForSize; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 122 template <typename T> | 124 template <typename T> |
| 123 T BinaryComplement(T x) { | 125 T BinaryComplement(T x) { |
| 124 return ~x; | 126 return ~x; |
| 125 } | 127 } |
| 126 | 128 |
| 127 // Here are the actual portable checked integer math implementations. | 129 // Here are the actual portable checked integer math implementations. |
| 128 // TODO(jschuh): Break this code out from the enable_if pattern and find a clean | 130 // TODO(jschuh): Break this code out from the enable_if pattern and find a clean |
| 129 // way to coalesce things into the CheckedNumericState specializations below. | 131 // way to coalesce things into the CheckedNumericState specializations below. |
| 130 | 132 |
| 131 template <typename T> | 133 template <typename T> |
| 132 typename enable_if<std::numeric_limits<T>::is_integer, T>::type | 134 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type |
| 133 CheckedAdd(T x, T y, RangeConstraint* validity) { | 135 CheckedAdd(T x, T y, RangeConstraint* validity) { |
| 134 // Since the value of x+y is undefined if we have a signed type, we compute | 136 // Since the value of x+y is undefined if we have a signed type, we compute |
| 135 // it using the unsigned type of the same size. | 137 // it using the unsigned type of the same size. |
| 136 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; | 138 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; |
| 137 UnsignedDst ux = static_cast<UnsignedDst>(x); | 139 UnsignedDst ux = static_cast<UnsignedDst>(x); |
| 138 UnsignedDst uy = static_cast<UnsignedDst>(y); | 140 UnsignedDst uy = static_cast<UnsignedDst>(y); |
| 139 UnsignedDst uresult = ux + uy; | 141 UnsignedDst uresult = ux + uy; |
| 140 // Addition is valid if the sign of (x + y) is equal to either that of x or | 142 // Addition is valid if the sign of (x + y) is equal to either that of x or |
| 141 // that of y. | 143 // that of y. |
| 142 if (std::numeric_limits<T>::is_signed) { | 144 if (std::numeric_limits<T>::is_signed) { |
| 143 if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy)))) | 145 if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy)))) |
| 144 *validity = RANGE_VALID; | 146 *validity = RANGE_VALID; |
| 145 else // Direction of wrap is inverse of result sign. | 147 else // Direction of wrap is inverse of result sign. |
| 146 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; | 148 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; |
| 147 | 149 |
| 148 } else { // Unsigned is either valid or overflow. | 150 } else { // Unsigned is either valid or overflow. |
| 149 *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW; | 151 *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW; |
| 150 } | 152 } |
| 151 return static_cast<T>(uresult); | 153 return static_cast<T>(uresult); |
| 152 } | 154 } |
| 153 | 155 |
| 154 template <typename T> | 156 template <typename T> |
| 155 typename enable_if<std::numeric_limits<T>::is_integer, T>::type | 157 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type |
| 156 CheckedSub(T x, T y, RangeConstraint* validity) { | 158 CheckedSub(T x, T y, RangeConstraint* validity) { |
| 157 // 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 |
| 158 // it using the unsigned type of the same size. | 160 // it using the unsigned type of the same size. |
| 159 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; | 161 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; |
| 160 UnsignedDst ux = static_cast<UnsignedDst>(x); | 162 UnsignedDst ux = static_cast<UnsignedDst>(x); |
| 161 UnsignedDst uy = static_cast<UnsignedDst>(y); | 163 UnsignedDst uy = static_cast<UnsignedDst>(y); |
| 162 UnsignedDst uresult = ux - uy; | 164 UnsignedDst uresult = ux - uy; |
| 163 // Subtraction is valid if either x and y have same sign, or (x-y) and x have | 165 // Subtraction is valid if either x and y have same sign, or (x-y) and x have |
| 164 // the same sign. | 166 // the same sign. |
| 165 if (std::numeric_limits<T>::is_signed) { | 167 if (std::numeric_limits<T>::is_signed) { |
| 166 if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy)))) | 168 if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy)))) |
| 167 *validity = RANGE_VALID; | 169 *validity = RANGE_VALID; |
| 168 else // Direction of wrap is inverse of result sign. | 170 else // Direction of wrap is inverse of result sign. |
| 169 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; | 171 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; |
| 170 | 172 |
| 171 } else { // Unsigned is either valid or underflow. | 173 } else { // Unsigned is either valid or underflow. |
| 172 *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW; | 174 *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW; |
| 173 } | 175 } |
| 174 return static_cast<T>(uresult); | 176 return static_cast<T>(uresult); |
| 175 } | 177 } |
| 176 | 178 |
| 177 // Integer multiplication is a bit complicated. In the fast case we just | 179 // Integer multiplication is a bit complicated. In the fast case we just |
| 178 // we just promote to a twice wider type, and range check the result. In the | 180 // we just promote to a twice wider type, and range check the result. In the |
| 179 // slow case we need to manually check that the result won't be truncated by | 181 // slow case we need to manually check that the result won't be truncated by |
| 180 // checking with division against the appropriate bound. | 182 // checking with division against the appropriate bound. |
| 181 template <typename T> | 183 template <typename T> |
| 182 typename enable_if< | 184 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 183 std::numeric_limits<T>::is_integer && sizeof(T) * 2 <= sizeof(uintmax_t), | 185 sizeof(T) * 2 <= sizeof(uintmax_t), |
| 184 T>::type | 186 T>::type |
| 185 CheckedMul(T x, T y, RangeConstraint* validity) { | 187 CheckedMul(T x, T y, RangeConstraint* validity) { |
| 186 typedef typename TwiceWiderInteger<T>::type IntermediateType; | 188 typedef typename TwiceWiderInteger<T>::type IntermediateType; |
| 187 IntermediateType tmp = | 189 IntermediateType tmp = |
| 188 static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); | 190 static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); |
| 189 *validity = DstRangeRelationToSrcRange<T>(tmp); | 191 *validity = DstRangeRelationToSrcRange<T>(tmp); |
| 190 return static_cast<T>(tmp); | 192 return static_cast<T>(tmp); |
| 191 } | 193 } |
| 192 | 194 |
| 193 template <typename T> | 195 template <typename T> |
| 194 typename enable_if<std::numeric_limits<T>::is_integer&& std::numeric_limits< | 196 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 195 T>::is_signed&&(sizeof(T) * 2 > sizeof(uintmax_t)), | 197 std::numeric_limits<T>::is_signed && |
| 196 T>::type | 198 (sizeof(T) * 2 > sizeof(uintmax_t)), |
| 199 T>::type |
| 197 CheckedMul(T x, T y, RangeConstraint* validity) { | 200 CheckedMul(T x, T y, RangeConstraint* validity) { |
| 198 // If either side is zero then the result will be zero. | 201 // If either side is zero then the result will be zero. |
| 199 if (!x || !y) { | 202 if (!x || !y) { |
| 200 return RANGE_VALID; | 203 return RANGE_VALID; |
| 201 | 204 |
| 202 } else if (x > 0) { | 205 } else if (x > 0) { |
| 203 if (y > 0) | 206 if (y > 0) |
| 204 *validity = | 207 *validity = |
| 205 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW; | 208 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW; |
| 206 else | 209 else |
| 207 *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID | 210 *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID |
| 208 : RANGE_UNDERFLOW; | 211 : RANGE_UNDERFLOW; |
| 209 | 212 |
| 210 } else { | 213 } else { |
| 211 if (y > 0) | 214 if (y > 0) |
| 212 *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID | 215 *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID |
| 213 : RANGE_UNDERFLOW; | 216 : RANGE_UNDERFLOW; |
| 214 else | 217 else |
| 215 *validity = | 218 *validity = |
| 216 y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW; | 219 y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW; |
| 217 } | 220 } |
| 218 | 221 |
| 219 return x * y; | 222 return x * y; |
| 220 } | 223 } |
| 221 | 224 |
| 222 template <typename T> | 225 template <typename T> |
| 223 typename enable_if<std::numeric_limits<T>::is_integer && | 226 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 224 !std::numeric_limits<T>::is_signed && | 227 !std::numeric_limits<T>::is_signed && |
| 225 (sizeof(T) * 2 > sizeof(uintmax_t)), | 228 (sizeof(T) * 2 > sizeof(uintmax_t)), |
| 226 T>::type | 229 T>::type |
| 227 CheckedMul(T x, T y, RangeConstraint* validity) { | 230 CheckedMul(T x, T y, RangeConstraint* validity) { |
| 228 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y) | 231 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y) |
| 229 ? RANGE_VALID | 232 ? RANGE_VALID |
| 230 : RANGE_OVERFLOW; | 233 : RANGE_OVERFLOW; |
| 231 return x * y; | 234 return x * y; |
| 232 } | 235 } |
| 233 | 236 |
| 234 // Division just requires a check for an invalid negation on signed min/-1. | 237 // Division just requires a check for an invalid negation on signed min/-1. |
| 235 template <typename T> | 238 template <typename T> |
| 236 T CheckedDiv( | 239 T CheckedDiv(T x, |
| 237 T x, | 240 T y, |
| 238 T y, | 241 RangeConstraint* validity, |
| 239 RangeConstraint* validity, | 242 typename std::enable_if<std::numeric_limits<T>::is_integer, |
| 240 typename enable_if<std::numeric_limits<T>::is_integer, int>::type = 0) { | 243 int>::type = 0) { |
| 241 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() && | 244 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() && |
| 242 y == static_cast<T>(-1)) { | 245 y == static_cast<T>(-1)) { |
| 243 *validity = RANGE_OVERFLOW; | 246 *validity = RANGE_OVERFLOW; |
| 244 return std::numeric_limits<T>::min(); | 247 return std::numeric_limits<T>::min(); |
| 245 } | 248 } |
| 246 | 249 |
| 247 *validity = RANGE_VALID; | 250 *validity = RANGE_VALID; |
| 248 return x / y; | 251 return x / y; |
| 249 } | 252 } |
| 250 | 253 |
| 251 template <typename T> | 254 template <typename T> |
| 252 typename enable_if< | 255 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 253 std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, | 256 std::numeric_limits<T>::is_signed, |
| 254 T>::type | 257 T>::type |
| 255 CheckedMod(T x, T y, RangeConstraint* validity) { | 258 CheckedMod(T x, T y, RangeConstraint* validity) { |
| 256 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; | 259 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; |
| 257 return x % y; | 260 return x % y; |
| 258 } | 261 } |
| 259 | 262 |
| 260 template <typename T> | 263 template <typename T> |
| 261 typename enable_if< | 264 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 262 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, | 265 !std::numeric_limits<T>::is_signed, |
| 263 T>::type | 266 T>::type |
| 264 CheckedMod(T x, T y, RangeConstraint* validity) { | 267 CheckedMod(T x, T y, RangeConstraint* validity) { |
| 265 *validity = RANGE_VALID; | 268 *validity = RANGE_VALID; |
| 266 return x % y; | 269 return x % y; |
| 267 } | 270 } |
| 268 | 271 |
| 269 template <typename T> | 272 template <typename T> |
| 270 typename enable_if< | 273 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 271 std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, | 274 std::numeric_limits<T>::is_signed, |
| 272 T>::type | 275 T>::type |
| 273 CheckedNeg(T value, RangeConstraint* validity) { | 276 CheckedNeg(T value, RangeConstraint* validity) { |
| 274 *validity = | 277 *validity = |
| 275 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; | 278 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; |
| 276 // The negation of signed min is min, so catch that one. | 279 // The negation of signed min is min, so catch that one. |
| 277 return -value; | 280 return -value; |
| 278 } | 281 } |
| 279 | 282 |
| 280 template <typename T> | 283 template <typename T> |
| 281 typename enable_if< | 284 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 282 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, | 285 !std::numeric_limits<T>::is_signed, |
| 283 T>::type | 286 T>::type |
| 284 CheckedNeg(T value, RangeConstraint* validity) { | 287 CheckedNeg(T value, RangeConstraint* validity) { |
| 285 // The only legal unsigned negation is zero. | 288 // The only legal unsigned negation is zero. |
| 286 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; | 289 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; |
| 287 return static_cast<T>( | 290 return static_cast<T>( |
| 288 -static_cast<typename SignedIntegerForSize<T>::type>(value)); | 291 -static_cast<typename SignedIntegerForSize<T>::type>(value)); |
| 289 } | 292 } |
| 290 | 293 |
| 291 template <typename T> | 294 template <typename T> |
| 292 typename enable_if< | 295 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 293 std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, | 296 std::numeric_limits<T>::is_signed, |
| 294 T>::type | 297 T>::type |
| 295 CheckedAbs(T value, RangeConstraint* validity) { | 298 CheckedAbs(T value, RangeConstraint* validity) { |
| 296 *validity = | 299 *validity = |
| 297 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; | 300 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; |
| 298 return static_cast<T>(std::abs(value)); | 301 return static_cast<T>(std::abs(value)); |
| 299 } | 302 } |
| 300 | 303 |
| 301 template <typename T> | 304 template <typename T> |
| 302 typename enable_if< | 305 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 303 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, | 306 !std::numeric_limits<T>::is_signed, |
| 304 T>::type | 307 T>::type |
| 305 CheckedAbs(T value, RangeConstraint* validity) { | 308 CheckedAbs(T value, RangeConstraint* validity) { |
| 306 // T is unsigned, so |value| must already be positive. | 309 // T is unsigned, so |value| must already be positive. |
| 307 *validity = RANGE_VALID; | 310 *validity = RANGE_VALID; |
| 308 return value; | 311 return value; |
| 309 } | 312 } |
| 310 | 313 |
| 311 template <typename T> | 314 template <typename T> |
| 312 typename enable_if<std::numeric_limits<T>::is_integer && | 315 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 313 std::numeric_limits<T>::is_signed, | 316 std::numeric_limits<T>::is_signed, |
| 314 typename UnsignedIntegerForSize<T>::type>::type | 317 typename UnsignedIntegerForSize<T>::type>::type |
| 315 CheckedUnsignedAbs(T value) { | 318 CheckedUnsignedAbs(T value) { |
| 316 typedef typename UnsignedIntegerForSize<T>::type UnsignedT; | 319 typedef typename UnsignedIntegerForSize<T>::type UnsignedT; |
| 317 return value == std::numeric_limits<T>::min() | 320 return value == std::numeric_limits<T>::min() |
| 318 ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1 | 321 ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1 |
| 319 : static_cast<UnsignedT>(std::abs(value)); | 322 : static_cast<UnsignedT>(std::abs(value)); |
| 320 } | 323 } |
| 321 | 324 |
| 322 template <typename T> | 325 template <typename T> |
| 323 typename enable_if<std::numeric_limits<T>::is_integer && | 326 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 324 !std::numeric_limits<T>::is_signed, | 327 !std::numeric_limits<T>::is_signed, |
| 325 T>::type | 328 T>::type |
| 326 CheckedUnsignedAbs(T value) { | 329 CheckedUnsignedAbs(T value) { |
| 327 // T is unsigned, so |value| must already be positive. | 330 // T is unsigned, so |value| must already be positive. |
| 328 return value; | 331 return value; |
| 329 } | 332 } |
| 330 | 333 |
| 331 // These are the floating point stubs that the compiler needs to see. Only the | 334 // These are the floating point stubs that the compiler needs to see. Only the |
| 332 // negation operation is ever called. | 335 // negation operation is ever called. |
| 333 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ | 336 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ |
| 334 template <typename T> \ | 337 template <typename T> \ |
| 335 typename enable_if<std::numeric_limits<T>::is_iec559, T>::type \ | 338 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \ |
| 336 Checked##NAME(T, T, RangeConstraint*) { \ | 339 Checked##NAME(T, T, RangeConstraint*) { \ |
| 337 NOTREACHED(); \ | 340 NOTREACHED(); \ |
| 338 return 0; \ | 341 return 0; \ |
| 339 } | 342 } |
| 340 | 343 |
| 341 BASE_FLOAT_ARITHMETIC_STUBS(Add) | 344 BASE_FLOAT_ARITHMETIC_STUBS(Add) |
| 342 BASE_FLOAT_ARITHMETIC_STUBS(Sub) | 345 BASE_FLOAT_ARITHMETIC_STUBS(Sub) |
| 343 BASE_FLOAT_ARITHMETIC_STUBS(Mul) | 346 BASE_FLOAT_ARITHMETIC_STUBS(Mul) |
| 344 BASE_FLOAT_ARITHMETIC_STUBS(Div) | 347 BASE_FLOAT_ARITHMETIC_STUBS(Div) |
| 345 BASE_FLOAT_ARITHMETIC_STUBS(Mod) | 348 BASE_FLOAT_ARITHMETIC_STUBS(Mod) |
| 346 | 349 |
| 347 #undef BASE_FLOAT_ARITHMETIC_STUBS | 350 #undef BASE_FLOAT_ARITHMETIC_STUBS |
| 348 | 351 |
| 349 template <typename T> | 352 template <typename T> |
| 350 typename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg( | 353 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg( |
| 351 T value, | 354 T value, |
| 352 RangeConstraint*) { | 355 RangeConstraint*) { |
| 353 return -value; | 356 return -value; |
| 354 } | 357 } |
| 355 | 358 |
| 356 template <typename T> | 359 template <typename T> |
| 357 typename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs( | 360 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs( |
| 358 T value, | 361 T value, |
| 359 RangeConstraint*) { | 362 RangeConstraint*) { |
| 360 return std::abs(value); | 363 return std::abs(value); |
| 361 } | 364 } |
| 362 | 365 |
| 363 // Floats carry around their validity state with them, but integers do not. So, | 366 // Floats carry around their validity state with them, but integers do not. So, |
| 364 // we wrap the underlying value in a specialization in order to hide that detail | 367 // we wrap the underlying value in a specialization in order to hide that detail |
| 365 // and expose an interface via accessors. | 368 // and expose an interface via accessors. |
| 366 enum NumericRepresentation { | 369 enum NumericRepresentation { |
| 367 NUMERIC_INTEGER, | 370 NUMERIC_INTEGER, |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 407 // Copy constructor. | 410 // Copy constructor. |
| 408 template <typename Src> | 411 template <typename Src> |
| 409 CheckedNumericState(const CheckedNumericState<Src>& rhs) | 412 CheckedNumericState(const CheckedNumericState<Src>& rhs) |
| 410 : value_(static_cast<T>(rhs.value())), | 413 : value_(static_cast<T>(rhs.value())), |
| 411 validity_(GetRangeConstraint( | 414 validity_(GetRangeConstraint( |
| 412 rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {} | 415 rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {} |
| 413 | 416 |
| 414 template <typename Src> | 417 template <typename Src> |
| 415 explicit CheckedNumericState( | 418 explicit CheckedNumericState( |
| 416 Src value, | 419 Src value, |
| 417 typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type = | 420 typename std::enable_if<std::numeric_limits<Src>::is_specialized, |
| 418 0) | 421 int>::type = 0) |
| 419 : value_(static_cast<T>(value)), | 422 : value_(static_cast<T>(value)), |
| 420 validity_(DstRangeRelationToSrcRange<T>(value)) {} | 423 validity_(DstRangeRelationToSrcRange<T>(value)) {} |
| 421 | 424 |
| 422 RangeConstraint validity() const { return validity_; } | 425 RangeConstraint validity() const { return validity_; } |
| 423 T value() const { return value_; } | 426 T value() const { return value_; } |
| 424 }; | 427 }; |
| 425 | 428 |
| 426 // Floating points maintain their own validity, but need translation wrappers. | 429 // Floating points maintain their own validity, but need translation wrappers. |
| 427 template <typename T> | 430 template <typename T> |
| 428 class CheckedNumericState<T, NUMERIC_FLOATING> { | 431 class CheckedNumericState<T, NUMERIC_FLOATING> { |
| 429 private: | 432 private: |
| 430 T value_; | 433 T value_; |
| 431 | 434 |
| 432 public: | 435 public: |
| 433 template <typename Src, NumericRepresentation type> | 436 template <typename Src, NumericRepresentation type> |
| 434 friend class CheckedNumericState; | 437 friend class CheckedNumericState; |
| 435 | 438 |
| 436 CheckedNumericState() : value_(0.0) {} | 439 CheckedNumericState() : value_(0.0) {} |
| 437 | 440 |
| 438 template <typename Src> | 441 template <typename Src> |
| 439 CheckedNumericState( | 442 CheckedNumericState( |
| 440 Src value, | 443 Src value, |
| 441 RangeConstraint validity, | 444 RangeConstraint validity, |
| 442 typename enable_if<std::numeric_limits<Src>::is_integer, int>::type = 0) { | 445 typename std::enable_if<std::numeric_limits<Src>::is_integer, int>::type = |
| 446 0) { |
| 443 switch (DstRangeRelationToSrcRange<T>(value)) { | 447 switch (DstRangeRelationToSrcRange<T>(value)) { |
| 444 case RANGE_VALID: | 448 case RANGE_VALID: |
| 445 value_ = static_cast<T>(value); | 449 value_ = static_cast<T>(value); |
| 446 break; | 450 break; |
| 447 | 451 |
| 448 case RANGE_UNDERFLOW: | 452 case RANGE_UNDERFLOW: |
| 449 value_ = -std::numeric_limits<T>::infinity(); | 453 value_ = -std::numeric_limits<T>::infinity(); |
| 450 break; | 454 break; |
| 451 | 455 |
| 452 case RANGE_OVERFLOW: | 456 case RANGE_OVERFLOW: |
| 453 value_ = std::numeric_limits<T>::infinity(); | 457 value_ = std::numeric_limits<T>::infinity(); |
| 454 break; | 458 break; |
| 455 | 459 |
| 456 case RANGE_INVALID: | 460 case RANGE_INVALID: |
| 457 value_ = std::numeric_limits<T>::quiet_NaN(); | 461 value_ = std::numeric_limits<T>::quiet_NaN(); |
| 458 break; | 462 break; |
| 459 | 463 |
| 460 default: | 464 default: |
| 461 NOTREACHED(); | 465 NOTREACHED(); |
| 462 } | 466 } |
| 463 } | 467 } |
| 464 | 468 |
| 465 template <typename Src> | 469 template <typename Src> |
| 466 explicit CheckedNumericState( | 470 explicit CheckedNumericState( |
| 467 Src value, | 471 Src value, |
| 468 typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type = | 472 typename std::enable_if<std::numeric_limits<Src>::is_specialized, |
| 469 0) | 473 int>::type = 0) |
| 470 : value_(static_cast<T>(value)) {} | 474 : value_(static_cast<T>(value)) {} |
| 471 | 475 |
| 472 // Copy constructor. | 476 // Copy constructor. |
| 473 template <typename Src> | 477 template <typename Src> |
| 474 CheckedNumericState(const CheckedNumericState<Src>& rhs) | 478 CheckedNumericState(const CheckedNumericState<Src>& rhs) |
| 475 : value_(static_cast<T>(rhs.value())) {} | 479 : value_(static_cast<T>(rhs.value())) {} |
| 476 | 480 |
| 477 RangeConstraint validity() const { | 481 RangeConstraint validity() const { |
| 478 return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(), | 482 return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(), |
| 479 value_ >= -std::numeric_limits<T>::max()); | 483 value_ >= -std::numeric_limits<T>::max()); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 531 sizeof(T) >= (2 * sizeof(Lhs)) && | 535 sizeof(T) >= (2 * sizeof(Lhs)) && |
| 532 StaticDstRangeRelationToSrcRange<T, Rhs>::value != | 536 StaticDstRangeRelationToSrcRange<T, Rhs>::value != |
| 533 NUMERIC_RANGE_CONTAINED && | 537 NUMERIC_RANGE_CONTAINED && |
| 534 sizeof(T) >= (2 * sizeof(Rhs)); | 538 sizeof(T) >= (2 * sizeof(Rhs)); |
| 535 }; | 539 }; |
| 536 | 540 |
| 537 } // namespace internal | 541 } // namespace internal |
| 538 } // namespace base | 542 } // namespace base |
| 539 | 543 |
| 540 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ | 544 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ |
| OLD | NEW |