| 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 PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ | 5 #ifndef PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ |
| 6 #define PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ | 6 #define PDFIUM_THIRD_PARTY_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 "safe_conversions.h" | 15 #include "safe_conversions.h" |
| 15 #include "third_party/base/macros.h" | 16 #include "third_party/base/macros.h" |
| 16 #include "third_party/base/template_util.h" | |
| 17 | 17 |
| 18 namespace pdfium { | 18 namespace pdfium { |
| 19 namespace base { | 19 namespace base { |
| 20 namespace internal { | 20 namespace internal { |
| 21 | 21 |
| 22 // Everything from here up to the floating point operations is portable C++, | 22 // Everything from here up to the floating point operations is portable C++, |
| 23 // but it may not be fast. This code could be split based on | 23 // but it may not be fast. This code could be split based on |
| 24 // platform/architecture and replaced with potentially faster implementations. | 24 // platform/architecture and replaced with potentially faster implementations. |
| 25 | 25 |
| 26 // Integer promotion templates used by the portable checked integer arithmetic. | 26 // Integer promotion templates used by the portable checked integer arithmetic. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 struct IntegerForSizeAndSign<8, false> { | 58 struct IntegerForSizeAndSign<8, false> { |
| 59 typedef uint64_t type; | 59 typedef uint64_t type; |
| 60 }; | 60 }; |
| 61 | 61 |
| 62 // WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to | 62 // WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to |
| 63 // support 128-bit math, then the ArithmeticPromotion template below will need | 63 // support 128-bit math, then the ArithmeticPromotion template below will need |
| 64 // to be updated (or more likely replaced with a decltype expression). | 64 // to be updated (or more likely replaced with a decltype expression). |
| 65 | 65 |
| 66 template <typename Integer> | 66 template <typename Integer> |
| 67 struct UnsignedIntegerForSize { | 67 struct UnsignedIntegerForSize { |
| 68 typedef typename enable_if< | 68 typedef typename std::enable_if< |
| 69 std::numeric_limits<Integer>::is_integer, | 69 std::numeric_limits<Integer>::is_integer, |
| 70 typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type type; | 70 typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type type; |
| 71 }; | 71 }; |
| 72 | 72 |
| 73 template <typename Integer> | 73 template <typename Integer> |
| 74 struct SignedIntegerForSize { | 74 struct SignedIntegerForSize { |
| 75 typedef typename enable_if< | 75 typedef typename std::enable_if< |
| 76 std::numeric_limits<Integer>::is_integer, | 76 std::numeric_limits<Integer>::is_integer, |
| 77 typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type type; | 77 typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type type; |
| 78 }; | 78 }; |
| 79 | 79 |
| 80 template <typename Integer> | 80 template <typename Integer> |
| 81 struct TwiceWiderInteger { | 81 struct TwiceWiderInteger { |
| 82 typedef typename enable_if< | 82 typedef typename std::enable_if< |
| 83 std::numeric_limits<Integer>::is_integer, | 83 std::numeric_limits<Integer>::is_integer, |
| 84 typename IntegerForSizeAndSign< | 84 typename IntegerForSizeAndSign< |
| 85 sizeof(Integer) * 2, | 85 sizeof(Integer) * 2, |
| 86 std::numeric_limits<Integer>::is_signed>::type>::type type; | 86 std::numeric_limits<Integer>::is_signed>::type>::type type; |
| 87 }; | 87 }; |
| 88 | 88 |
| 89 template <typename Integer> | 89 template <typename Integer> |
| 90 struct PositionOfSignBit { | 90 struct PositionOfSignBit { |
| 91 static const typename 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 = 8 * sizeof(Integer) - 1; | 92 size_t>::type value = |
| 93 8 * sizeof(Integer) - 1; |
| 93 }; | 94 }; |
| 94 | 95 |
| 95 // Helper templates for integer manipulations. | 96 // Helper templates for integer manipulations. |
| 96 | 97 |
| 97 template <typename T> | 98 template <typename T> |
| 98 bool HasSignBit(T x) { | 99 bool HasSignBit(T x) { |
| 99 // Cast to unsigned since right shift on signed is undefined. | 100 // Cast to unsigned since right shift on signed is undefined. |
| 100 return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >> | 101 return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >> |
| 101 PositionOfSignBit<T>::value); | 102 PositionOfSignBit<T>::value); |
| 102 } | 103 } |
| 103 | 104 |
| 104 // This wrapper undoes the standard integer promotions. | 105 // This wrapper undoes the standard integer promotions. |
| 105 template <typename T> | 106 template <typename T> |
| 106 T BinaryComplement(T x) { | 107 T BinaryComplement(T x) { |
| 107 return ~x; | 108 return ~x; |
| 108 } | 109 } |
| 109 | 110 |
| 110 // Here are the actual portable checked integer math implementations. | 111 // Here are the actual portable checked integer math implementations. |
| 111 // TODO(jschuh): Break this code out from the enable_if pattern and find a clean | 112 // TODO(jschuh): Break this code out from the enable_if pattern and find a clean |
| 112 // way to coalesce things into the CheckedNumericState specializations below. | 113 // way to coalesce things into the CheckedNumericState specializations below. |
| 113 | 114 |
| 114 template <typename T> | 115 template <typename T> |
| 115 typename enable_if<std::numeric_limits<T>::is_integer, T>::type | 116 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type |
| 116 CheckedAdd(T x, T y, RangeConstraint* validity) { | 117 CheckedAdd(T x, T y, RangeConstraint* validity) { |
| 117 // Since the value of x+y is undefined if we have a signed type, we compute | 118 // Since the value of x+y is undefined if we have a signed type, we compute |
| 118 // it using the unsigned type of the same size. | 119 // it using the unsigned type of the same size. |
| 119 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; | 120 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; |
| 120 UnsignedDst ux = static_cast<UnsignedDst>(x); | 121 UnsignedDst ux = static_cast<UnsignedDst>(x); |
| 121 UnsignedDst uy = static_cast<UnsignedDst>(y); | 122 UnsignedDst uy = static_cast<UnsignedDst>(y); |
| 122 UnsignedDst uresult = ux + uy; | 123 UnsignedDst uresult = ux + uy; |
| 123 // Addition is valid if the sign of (x + y) is equal to either that of x or | 124 // Addition is valid if the sign of (x + y) is equal to either that of x or |
| 124 // that of y. | 125 // that of y. |
| 125 if (std::numeric_limits<T>::is_signed) { | 126 if (std::numeric_limits<T>::is_signed) { |
| 126 if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy)))) | 127 if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy)))) |
| 127 *validity = RANGE_VALID; | 128 *validity = RANGE_VALID; |
| 128 else // Direction of wrap is inverse of result sign. | 129 else // Direction of wrap is inverse of result sign. |
| 129 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; | 130 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; |
| 130 | 131 |
| 131 } else { // Unsigned is either valid or overflow. | 132 } else { // Unsigned is either valid or overflow. |
| 132 *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW; | 133 *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW; |
| 133 } | 134 } |
| 134 return static_cast<T>(uresult); | 135 return static_cast<T>(uresult); |
| 135 } | 136 } |
| 136 | 137 |
| 137 template <typename T> | 138 template <typename T> |
| 138 typename enable_if<std::numeric_limits<T>::is_integer, T>::type | 139 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type |
| 139 CheckedSub(T x, T y, RangeConstraint* validity) { | 140 CheckedSub(T x, T y, RangeConstraint* validity) { |
| 140 // Since the value of x+y is undefined if we have a signed type, we compute | 141 // Since the value of x+y is undefined if we have a signed type, we compute |
| 141 // it using the unsigned type of the same size. | 142 // it using the unsigned type of the same size. |
| 142 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; | 143 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; |
| 143 UnsignedDst ux = static_cast<UnsignedDst>(x); | 144 UnsignedDst ux = static_cast<UnsignedDst>(x); |
| 144 UnsignedDst uy = static_cast<UnsignedDst>(y); | 145 UnsignedDst uy = static_cast<UnsignedDst>(y); |
| 145 UnsignedDst uresult = ux - uy; | 146 UnsignedDst uresult = ux - uy; |
| 146 // Subtraction is valid if either x and y have same sign, or (x-y) and x have | 147 // Subtraction is valid if either x and y have same sign, or (x-y) and x have |
| 147 // the same sign. | 148 // the same sign. |
| 148 if (std::numeric_limits<T>::is_signed) { | 149 if (std::numeric_limits<T>::is_signed) { |
| 149 if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy)))) | 150 if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy)))) |
| 150 *validity = RANGE_VALID; | 151 *validity = RANGE_VALID; |
| 151 else // Direction of wrap is inverse of result sign. | 152 else // Direction of wrap is inverse of result sign. |
| 152 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; | 153 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; |
| 153 | 154 |
| 154 } else { // Unsigned is either valid or underflow. | 155 } else { // Unsigned is either valid or underflow. |
| 155 *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW; | 156 *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW; |
| 156 } | 157 } |
| 157 return static_cast<T>(uresult); | 158 return static_cast<T>(uresult); |
| 158 } | 159 } |
| 159 | 160 |
| 160 // Integer multiplication is a bit complicated. In the fast case we just | 161 // Integer multiplication is a bit complicated. In the fast case we just |
| 161 // we just promote to a twice wider type, and range check the result. In the | 162 // we just promote to a twice wider type, and range check the result. In the |
| 162 // slow case we need to manually check that the result won't be truncated by | 163 // slow case we need to manually check that the result won't be truncated by |
| 163 // checking with division against the appropriate bound. | 164 // checking with division against the appropriate bound. |
| 164 template <typename T> | 165 template <typename T> |
| 165 typename enable_if< | 166 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 166 std::numeric_limits<T>::is_integer && sizeof(T) * 2 <= sizeof(uintmax_t), | 167 sizeof(T) * 2 <= sizeof(uintmax_t), |
| 167 T>::type | 168 T>::type |
| 168 CheckedMul(T x, T y, RangeConstraint* validity) { | 169 CheckedMul(T x, T y, RangeConstraint* validity) { |
| 169 typedef typename TwiceWiderInteger<T>::type IntermediateType; | 170 typedef typename TwiceWiderInteger<T>::type IntermediateType; |
| 170 IntermediateType tmp = | 171 IntermediateType tmp = |
| 171 static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); | 172 static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); |
| 172 *validity = DstRangeRelationToSrcRange<T>(tmp); | 173 *validity = DstRangeRelationToSrcRange<T>(tmp); |
| 173 return static_cast<T>(tmp); | 174 return static_cast<T>(tmp); |
| 174 } | 175 } |
| 175 | 176 |
| 176 template <typename T> | 177 template <typename T> |
| 177 typename enable_if<std::numeric_limits<T>::is_integer&& std::numeric_limits< | 178 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 178 T>::is_signed&&(sizeof(T) * 2 > sizeof(uintmax_t)), | 179 std::numeric_limits<T>::is_signed && |
| 179 T>::type | 180 (sizeof(T) * 2 > sizeof(uintmax_t)), |
| 181 T>::type |
| 180 CheckedMul(T x, T y, RangeConstraint* validity) { | 182 CheckedMul(T x, T y, RangeConstraint* validity) { |
| 181 // If either side is zero then the result will be zero. | 183 // If either side is zero then the result will be zero. |
| 182 if (!x || !y) { | 184 if (!x || !y) { |
| 183 return RANGE_VALID; | 185 return RANGE_VALID; |
| 184 | 186 |
| 185 } else if (x > 0) { | 187 } else if (x > 0) { |
| 186 if (y > 0) | 188 if (y > 0) |
| 187 *validity = | 189 *validity = |
| 188 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW; | 190 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW; |
| 189 else | 191 else |
| 190 *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID | 192 *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID |
| 191 : RANGE_UNDERFLOW; | 193 : RANGE_UNDERFLOW; |
| 192 | 194 |
| 193 } else { | 195 } else { |
| 194 if (y > 0) | 196 if (y > 0) |
| 195 *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID | 197 *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID |
| 196 : RANGE_UNDERFLOW; | 198 : RANGE_UNDERFLOW; |
| 197 else | 199 else |
| 198 *validity = | 200 *validity = |
| 199 y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW; | 201 y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW; |
| 200 } | 202 } |
| 201 | 203 |
| 202 return x * y; | 204 return x * y; |
| 203 } | 205 } |
| 204 | 206 |
| 205 template <typename T> | 207 template <typename T> |
| 206 typename enable_if<std::numeric_limits<T>::is_integer && | 208 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 207 !std::numeric_limits<T>::is_signed && | 209 !std::numeric_limits<T>::is_signed && |
| 208 (sizeof(T) * 2 > sizeof(uintmax_t)), | 210 (sizeof(T) * 2 > sizeof(uintmax_t)), |
| 209 T>::type | 211 T>::type |
| 210 CheckedMul(T x, T y, RangeConstraint* validity) { | 212 CheckedMul(T x, T y, RangeConstraint* validity) { |
| 211 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y) | 213 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y) |
| 212 ? RANGE_VALID | 214 ? RANGE_VALID |
| 213 : RANGE_OVERFLOW; | 215 : RANGE_OVERFLOW; |
| 214 return x * y; | 216 return x * y; |
| 215 } | 217 } |
| 216 | 218 |
| 217 // Division just requires a check for an invalid negation on signed min/-1. | 219 // Division just requires a check for an invalid negation on signed min/-1. |
| 218 template <typename T> | 220 template <typename T> |
| 219 T CheckedDiv( | 221 T CheckedDiv(T x, |
| 220 T x, | 222 T y, |
| 221 T y, | 223 RangeConstraint* validity, |
| 222 RangeConstraint* validity, | 224 typename std::enable_if<std::numeric_limits<T>::is_integer, |
| 223 typename enable_if<std::numeric_limits<T>::is_integer, int>::type = 0) { | 225 int>::type = 0) { |
| 224 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() && | 226 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() && |
| 225 y == static_cast<T>(-1)) { | 227 y == static_cast<T>(-1)) { |
| 226 *validity = RANGE_OVERFLOW; | 228 *validity = RANGE_OVERFLOW; |
| 227 return std::numeric_limits<T>::min(); | 229 return std::numeric_limits<T>::min(); |
| 228 } | 230 } |
| 229 | 231 |
| 230 *validity = RANGE_VALID; | 232 *validity = RANGE_VALID; |
| 231 return x / y; | 233 return x / y; |
| 232 } | 234 } |
| 233 | 235 |
| 234 template <typename T> | 236 template <typename T> |
| 235 typename enable_if< | 237 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 236 std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, | 238 std::numeric_limits<T>::is_signed, |
| 237 T>::type | 239 T>::type |
| 238 CheckedMod(T x, T y, RangeConstraint* validity) { | 240 CheckedMod(T x, T y, RangeConstraint* validity) { |
| 239 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; | 241 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; |
| 240 return x % y; | 242 return x % y; |
| 241 } | 243 } |
| 242 | 244 |
| 243 template <typename T> | 245 template <typename T> |
| 244 typename enable_if< | 246 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 245 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, | 247 !std::numeric_limits<T>::is_signed, |
| 246 T>::type | 248 T>::type |
| 247 CheckedMod(T x, T y, RangeConstraint* validity) { | 249 CheckedMod(T x, T y, RangeConstraint* validity) { |
| 248 *validity = RANGE_VALID; | 250 *validity = RANGE_VALID; |
| 249 return x % y; | 251 return x % y; |
| 250 } | 252 } |
| 251 | 253 |
| 252 template <typename T> | 254 template <typename T> |
| 253 typename enable_if< | 255 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 254 std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, | 256 std::numeric_limits<T>::is_signed, |
| 255 T>::type | 257 T>::type |
| 256 CheckedNeg(T value, RangeConstraint* validity) { | 258 CheckedNeg(T value, RangeConstraint* validity) { |
| 257 *validity = | 259 *validity = |
| 258 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; | 260 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; |
| 259 // The negation of signed min is min, so catch that one. | 261 // The negation of signed min is min, so catch that one. |
| 260 return -value; | 262 return -value; |
| 261 } | 263 } |
| 262 | 264 |
| 263 template <typename T> | 265 template <typename T> |
| 264 typename enable_if< | 266 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 265 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, | 267 !std::numeric_limits<T>::is_signed, |
| 266 T>::type | 268 T>::type |
| 267 CheckedNeg(T value, RangeConstraint* validity) { | 269 CheckedNeg(T value, RangeConstraint* validity) { |
| 268 // The only legal unsigned negation is zero. | 270 // The only legal unsigned negation is zero. |
| 269 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; | 271 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; |
| 270 return static_cast<T>( | 272 return static_cast<T>( |
| 271 -static_cast<typename SignedIntegerForSize<T>::type>(value)); | 273 -static_cast<typename SignedIntegerForSize<T>::type>(value)); |
| 272 } | 274 } |
| 273 | 275 |
| 274 template <typename T> | 276 template <typename T> |
| 275 typename enable_if< | 277 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 276 std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, | 278 std::numeric_limits<T>::is_signed, |
| 277 T>::type | 279 T>::type |
| 278 CheckedAbs(T value, RangeConstraint* validity) { | 280 CheckedAbs(T value, RangeConstraint* validity) { |
| 279 *validity = | 281 *validity = |
| 280 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; | 282 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; |
| 281 return std::abs(value); | 283 return std::abs(value); |
| 282 } | 284 } |
| 283 | 285 |
| 284 template <typename T> | 286 template <typename T> |
| 285 typename enable_if< | 287 typename std::enable_if<std::numeric_limits<T>::is_integer && |
| 286 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, | 288 !std::numeric_limits<T>::is_signed, |
| 287 T>::type | 289 T>::type |
| 288 CheckedAbs(T value, RangeConstraint* validity) { | 290 CheckedAbs(T value, RangeConstraint* validity) { |
| 289 // Absolute value of a positive is just its identiy. | 291 // Absolute value of a positive is just its identiy. |
| 290 *validity = RANGE_VALID; | 292 *validity = RANGE_VALID; |
| 291 return value; | 293 return value; |
| 292 } | 294 } |
| 293 | 295 |
| 294 // These are the floating point stubs that the compiler needs to see. Only the | 296 // These are the floating point stubs that the compiler needs to see. Only the |
| 295 // negation operation is ever called. | 297 // negation operation is ever called. |
| 296 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ | 298 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ |
| 297 template <typename T> \ | 299 template <typename T> \ |
| 298 typename enable_if<std::numeric_limits<T>::is_iec559, T>::type \ | 300 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \ |
| 299 Checked##NAME(T, T, RangeConstraint*) { \ | 301 Checked##NAME(T, T, RangeConstraint*) { \ |
| 300 NOTREACHED(); \ | 302 NOTREACHED(); \ |
| 301 return 0; \ | 303 return 0; \ |
| 302 } | 304 } |
| 303 | 305 |
| 304 BASE_FLOAT_ARITHMETIC_STUBS(Add) | 306 BASE_FLOAT_ARITHMETIC_STUBS(Add) |
| 305 BASE_FLOAT_ARITHMETIC_STUBS(Sub) | 307 BASE_FLOAT_ARITHMETIC_STUBS(Sub) |
| 306 BASE_FLOAT_ARITHMETIC_STUBS(Mul) | 308 BASE_FLOAT_ARITHMETIC_STUBS(Mul) |
| 307 BASE_FLOAT_ARITHMETIC_STUBS(Div) | 309 BASE_FLOAT_ARITHMETIC_STUBS(Div) |
| 308 BASE_FLOAT_ARITHMETIC_STUBS(Mod) | 310 BASE_FLOAT_ARITHMETIC_STUBS(Mod) |
| 309 | 311 |
| 310 #undef BASE_FLOAT_ARITHMETIC_STUBS | 312 #undef BASE_FLOAT_ARITHMETIC_STUBS |
| 311 | 313 |
| 312 template <typename T> | 314 template <typename T> |
| 313 typename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg( | 315 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg( |
| 314 T value, | 316 T value, |
| 315 RangeConstraint*) { | 317 RangeConstraint*) { |
| 316 return -value; | 318 return -value; |
| 317 } | 319 } |
| 318 | 320 |
| 319 template <typename T> | 321 template <typename T> |
| 320 typename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs( | 322 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs( |
| 321 T value, | 323 T value, |
| 322 RangeConstraint*) { | 324 RangeConstraint*) { |
| 323 return std::abs(value); | 325 return std::abs(value); |
| 324 } | 326 } |
| 325 | 327 |
| 326 // Floats carry around their validity state with them, but integers do not. So, | 328 // Floats carry around their validity state with them, but integers do not. So, |
| 327 // we wrap the underlying value in a specialization in order to hide that detail | 329 // we wrap the underlying value in a specialization in order to hide that detail |
| 328 // and expose an interface via accessors. | 330 // and expose an interface via accessors. |
| 329 enum NumericRepresentation { | 331 enum NumericRepresentation { |
| 330 NUMERIC_INTEGER, | 332 NUMERIC_INTEGER, |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 370 // Copy constructor. | 372 // Copy constructor. |
| 371 template <typename Src> | 373 template <typename Src> |
| 372 CheckedNumericState(const CheckedNumericState<Src>& rhs) | 374 CheckedNumericState(const CheckedNumericState<Src>& rhs) |
| 373 : value_(static_cast<T>(rhs.value())), | 375 : value_(static_cast<T>(rhs.value())), |
| 374 validity_(GetRangeConstraint( | 376 validity_(GetRangeConstraint( |
| 375 rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {} | 377 rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {} |
| 376 | 378 |
| 377 template <typename Src> | 379 template <typename Src> |
| 378 explicit CheckedNumericState( | 380 explicit CheckedNumericState( |
| 379 Src value, | 381 Src value, |
| 380 typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type = | 382 typename std::enable_if<std::numeric_limits<Src>::is_specialized, |
| 381 0) | 383 int>::type = 0) |
| 382 : value_(static_cast<T>(value)), | 384 : value_(static_cast<T>(value)), |
| 383 validity_(DstRangeRelationToSrcRange<T>(value)) {} | 385 validity_(DstRangeRelationToSrcRange<T>(value)) {} |
| 384 | 386 |
| 385 RangeConstraint validity() const { return validity_; } | 387 RangeConstraint validity() const { return validity_; } |
| 386 T value() const { return value_; } | 388 T value() const { return value_; } |
| 387 }; | 389 }; |
| 388 | 390 |
| 389 // Floating points maintain their own validity, but need translation wrappers. | 391 // Floating points maintain their own validity, but need translation wrappers. |
| 390 template <typename T> | 392 template <typename T> |
| 391 class CheckedNumericState<T, NUMERIC_FLOATING> { | 393 class CheckedNumericState<T, NUMERIC_FLOATING> { |
| 392 private: | 394 private: |
| 393 T value_; | 395 T value_; |
| 394 | 396 |
| 395 public: | 397 public: |
| 396 template <typename Src, NumericRepresentation type> | 398 template <typename Src, NumericRepresentation type> |
| 397 friend class CheckedNumericState; | 399 friend class CheckedNumericState; |
| 398 | 400 |
| 399 CheckedNumericState() : value_(0.0) {} | 401 CheckedNumericState() : value_(0.0) {} |
| 400 | 402 |
| 401 template <typename Src> | 403 template <typename Src> |
| 402 CheckedNumericState( | 404 CheckedNumericState( |
| 403 Src value, | 405 Src value, |
| 404 RangeConstraint validity, | 406 RangeConstraint validity, |
| 405 typename enable_if<std::numeric_limits<Src>::is_integer, int>::type = 0) { | 407 typename std::enable_if<std::numeric_limits<Src>::is_integer, int>::type = |
| 408 0) { |
| 406 switch (DstRangeRelationToSrcRange<T>(value)) { | 409 switch (DstRangeRelationToSrcRange<T>(value)) { |
| 407 case RANGE_VALID: | 410 case RANGE_VALID: |
| 408 value_ = static_cast<T>(value); | 411 value_ = static_cast<T>(value); |
| 409 break; | 412 break; |
| 410 | 413 |
| 411 case RANGE_UNDERFLOW: | 414 case RANGE_UNDERFLOW: |
| 412 value_ = -std::numeric_limits<T>::infinity(); | 415 value_ = -std::numeric_limits<T>::infinity(); |
| 413 break; | 416 break; |
| 414 | 417 |
| 415 case RANGE_OVERFLOW: | 418 case RANGE_OVERFLOW: |
| 416 value_ = std::numeric_limits<T>::infinity(); | 419 value_ = std::numeric_limits<T>::infinity(); |
| 417 break; | 420 break; |
| 418 | 421 |
| 419 case RANGE_INVALID: | 422 case RANGE_INVALID: |
| 420 value_ = std::numeric_limits<T>::quiet_NaN(); | 423 value_ = std::numeric_limits<T>::quiet_NaN(); |
| 421 break; | 424 break; |
| 422 | 425 |
| 423 default: | 426 default: |
| 424 NOTREACHED(); | 427 NOTREACHED(); |
| 425 } | 428 } |
| 426 } | 429 } |
| 427 | 430 |
| 428 template <typename Src> | 431 template <typename Src> |
| 429 explicit CheckedNumericState( | 432 explicit CheckedNumericState( |
| 430 Src value, | 433 Src value, |
| 431 typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type = | 434 typename std::enable_if<std::numeric_limits<Src>::is_specialized, |
| 432 0) | 435 int>::type = 0) |
| 433 : value_(static_cast<T>(value)) {} | 436 : value_(static_cast<T>(value)) {} |
| 434 | 437 |
| 435 // Copy constructor. | 438 // Copy constructor. |
| 436 template <typename Src> | 439 template <typename Src> |
| 437 CheckedNumericState(const CheckedNumericState<Src>& rhs) | 440 CheckedNumericState(const CheckedNumericState<Src>& rhs) |
| 438 : value_(static_cast<T>(rhs.value())) {} | 441 : value_(static_cast<T>(rhs.value())) {} |
| 439 | 442 |
| 440 RangeConstraint validity() const { | 443 RangeConstraint validity() const { |
| 441 return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(), | 444 return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(), |
| 442 value_ >= -std::numeric_limits<T>::max()); | 445 value_ >= -std::numeric_limits<T>::max()); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 StaticDstRangeRelationToSrcRange<T, Rhs>::value != | 498 StaticDstRangeRelationToSrcRange<T, Rhs>::value != |
| 496 NUMERIC_RANGE_CONTAINED && | 499 NUMERIC_RANGE_CONTAINED && |
| 497 sizeof(T) >= (2 * sizeof(Rhs)); | 500 sizeof(T) >= (2 * sizeof(Rhs)); |
| 498 }; | 501 }; |
| 499 | 502 |
| 500 } // namespace internal | 503 } // namespace internal |
| 501 } // namespace base | 504 } // namespace base |
| 502 } // namespace pdfium | 505 } // namespace pdfium |
| 503 | 506 |
| 504 #endif // PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ | 507 #endif // PDFIUM_THIRD_PARTY_SAFE_MATH_IMPL_H_ |
| OLD | NEW |