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 |