|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * vim: set ts=8 sts=4 et sw=4 tw=99: |
|
3 * |
|
4 * Copyright (C) 2011 Apple Inc. All rights reserved. |
|
5 * |
|
6 * Redistribution and use in source and binary forms, with or without |
|
7 * modification, are permitted provided that the following conditions |
|
8 * are met: |
|
9 * 1. Redistributions of source code must retain the above copyright |
|
10 * notice, this list of conditions and the following disclaimer. |
|
11 * 2. Redistributions in binary form must reproduce the above copyright |
|
12 * notice, this list of conditions and the following disclaimer in the |
|
13 * documentation and/or other materials provided with the distribution. |
|
14 * |
|
15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
|
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
|
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
|
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
26 */ |
|
27 |
|
28 #ifndef yarr_CheckedArithmetic_h |
|
29 #define yarr_CheckedArithmetic_h |
|
30 |
|
31 #include "assembler/wtf/Assertions.h" |
|
32 |
|
33 #include <limits> |
|
34 #include <stdint.h> |
|
35 #include "mozilla/TypeTraits.h" |
|
36 |
|
37 #ifdef _MSC_VER |
|
38 # undef min |
|
39 # undef max |
|
40 #endif |
|
41 |
|
42 /* Checked<T> |
|
43 * |
|
44 * This class provides a mechanism to perform overflow-safe integer arithmetic |
|
45 * without having to manually ensure that you have all the required bounds checks |
|
46 * directly in your code. |
|
47 * |
|
48 * There are two modes of operation: |
|
49 * - The default is Checked<T, CrashOnOverflow>, and crashes at the point |
|
50 * and overflow has occurred. |
|
51 * - The alternative is Checked<T, RecordOverflow>, which uses an additional |
|
52 * byte of storage to track whether an overflow has occurred, subsequent |
|
53 * unchecked operations will crash if an overflow has occured |
|
54 * |
|
55 * It is possible to provide a custom overflow handler, in which case you need |
|
56 * to support these functions: |
|
57 * - void overflowed(); |
|
58 * This function is called when an operation has produced an overflow. |
|
59 * - bool hasOverflowed(); |
|
60 * This function must return true if overflowed() has been called on an |
|
61 * instance and false if it has not. |
|
62 * - void clearOverflow(); |
|
63 * Used to reset overflow tracking when a value is being overwritten with |
|
64 * a new value. |
|
65 * |
|
66 * Checked<T> works for all integer types, with the following caveats: |
|
67 * - Mixing signedness of operands is only supported for types narrower than |
|
68 * 64bits. |
|
69 * - It does have a performance impact, so tight loops may want to be careful |
|
70 * when using it. |
|
71 * |
|
72 */ |
|
73 |
|
74 namespace WTF { |
|
75 |
|
76 class CrashOnOverflow { |
|
77 protected: |
|
78 void overflowed() |
|
79 { |
|
80 CRASH(); |
|
81 } |
|
82 |
|
83 void clearOverflow() { } |
|
84 |
|
85 public: |
|
86 bool hasOverflowed() const { return false; } |
|
87 }; |
|
88 |
|
89 class RecordOverflow { |
|
90 protected: |
|
91 RecordOverflow() |
|
92 : m_overflowed(false) |
|
93 { |
|
94 } |
|
95 |
|
96 void overflowed() |
|
97 { |
|
98 m_overflowed = true; |
|
99 } |
|
100 |
|
101 void clearOverflow() |
|
102 { |
|
103 m_overflowed = false; |
|
104 } |
|
105 |
|
106 public: |
|
107 bool hasOverflowed() const { return m_overflowed; } |
|
108 |
|
109 private: |
|
110 unsigned char m_overflowed; |
|
111 }; |
|
112 |
|
113 template <typename T, class OverflowHandler = RecordOverflow> class Checked; |
|
114 template <typename T> struct RemoveChecked; |
|
115 template <typename T> struct RemoveChecked<Checked<T> >; |
|
116 |
|
117 template <typename Target, typename Source, bool targetSigned = ::std::numeric_limits<Target>::is_signed, bool sourceSigned = ::std::numeric_limits<Source>::is_signed> struct BoundsChecker; |
|
118 template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, false> { |
|
119 static bool inBounds(Source value) |
|
120 { |
|
121 // Same signedness so implicit type conversion will always increase precision |
|
122 // to widest type |
|
123 return value <= ::std::numeric_limits<Target>::max(); |
|
124 } |
|
125 }; |
|
126 |
|
127 template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, true> { |
|
128 static bool inBounds(Source value) |
|
129 { |
|
130 // Same signedness so implicit type conversion will always increase precision |
|
131 // to widest type |
|
132 return ::std::numeric_limits<Target>::min() <= value && value <= ::std::numeric_limits<Target>::max(); |
|
133 } |
|
134 }; |
|
135 |
|
136 template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, true> { |
|
137 static bool inBounds(Source value) |
|
138 { |
|
139 // Target is unsigned so any value less than zero is clearly unsafe |
|
140 if (value < 0) |
|
141 return false; |
|
142 // If our (unsigned) Target is the same or greater width we can |
|
143 // convert value to type Target without losing precision |
|
144 if (sizeof(Target) >= sizeof(Source)) |
|
145 return static_cast<Target>(value) <= ::std::numeric_limits<Target>::max(); |
|
146 // The signed Source type has greater precision than the target so |
|
147 // max(Target) -> Source will widen. |
|
148 return value <= static_cast<Source>(::std::numeric_limits<Target>::max()); |
|
149 } |
|
150 }; |
|
151 |
|
152 template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, false> { |
|
153 static bool inBounds(Source value) |
|
154 { |
|
155 // Signed target with an unsigned source |
|
156 if (sizeof(Target) <= sizeof(Source)) |
|
157 return value <= static_cast<Source>(::std::numeric_limits<Target>::max()); |
|
158 // Target is Wider than Source so we're guaranteed to fit any value in |
|
159 // unsigned Source |
|
160 return true; |
|
161 } |
|
162 }; |
|
163 |
|
164 template <typename Target, typename Source, bool SameType = mozilla::IsSame<Target, Source>::value> struct BoundsCheckElider; |
|
165 template <typename Target, typename Source> struct BoundsCheckElider<Target, Source, true> { |
|
166 static bool inBounds(Source) { return true; } |
|
167 }; |
|
168 template <typename Target, typename Source> struct BoundsCheckElider<Target, Source, false> : public BoundsChecker<Target, Source> { |
|
169 }; |
|
170 |
|
171 template <typename Target, typename Source> static inline bool isInBounds(Source value) |
|
172 { |
|
173 return BoundsCheckElider<Target, Source>::inBounds(value); |
|
174 } |
|
175 |
|
176 template <typename T> struct RemoveChecked { |
|
177 typedef T CleanType; |
|
178 static const CleanType DefaultValue = 0; |
|
179 }; |
|
180 |
|
181 template <typename T> struct RemoveChecked<Checked<T, CrashOnOverflow> > { |
|
182 typedef typename RemoveChecked<T>::CleanType CleanType; |
|
183 static const CleanType DefaultValue = 0; |
|
184 }; |
|
185 |
|
186 template <typename T> struct RemoveChecked<Checked<T, RecordOverflow> > { |
|
187 typedef typename RemoveChecked<T>::CleanType CleanType; |
|
188 static const CleanType DefaultValue = 0; |
|
189 }; |
|
190 |
|
191 // The ResultBase and SignednessSelector are used to workaround typeof not being |
|
192 // available in MSVC |
|
193 template <typename U, typename V, bool uIsBigger = (sizeof(U) > sizeof(V)), bool sameSize = (sizeof(U) == sizeof(V))> struct ResultBase; |
|
194 template <typename U, typename V> struct ResultBase<U, V, true, false> { |
|
195 typedef U ResultType; |
|
196 }; |
|
197 |
|
198 template <typename U, typename V> struct ResultBase<U, V, false, false> { |
|
199 typedef V ResultType; |
|
200 }; |
|
201 |
|
202 template <typename U> struct ResultBase<U, U, false, true> { |
|
203 typedef U ResultType; |
|
204 }; |
|
205 |
|
206 template <typename U, typename V, bool uIsSigned = ::std::numeric_limits<U>::is_signed, bool vIsSigned = ::std::numeric_limits<V>::is_signed> struct SignednessSelector; |
|
207 template <typename U, typename V> struct SignednessSelector<U, V, true, true> { |
|
208 typedef U ResultType; |
|
209 }; |
|
210 |
|
211 template <typename U, typename V> struct SignednessSelector<U, V, false, false> { |
|
212 typedef U ResultType; |
|
213 }; |
|
214 |
|
215 template <typename U, typename V> struct SignednessSelector<U, V, true, false> { |
|
216 typedef V ResultType; |
|
217 }; |
|
218 |
|
219 template <typename U, typename V> struct SignednessSelector<U, V, false, true> { |
|
220 typedef U ResultType; |
|
221 }; |
|
222 |
|
223 template <typename U, typename V> struct ResultBase<U, V, false, true> { |
|
224 typedef typename SignednessSelector<U, V>::ResultType ResultType; |
|
225 }; |
|
226 |
|
227 template <typename U, typename V> struct Result : ResultBase<typename RemoveChecked<U>::CleanType, typename RemoveChecked<V>::CleanType> { |
|
228 }; |
|
229 |
|
230 template <typename LHS, typename RHS, typename ResultType = typename Result<LHS, RHS>::ResultType, |
|
231 bool lhsSigned = ::std::numeric_limits<LHS>::is_signed, bool rhsSigned = ::std::numeric_limits<RHS>::is_signed> struct ArithmeticOperations; |
|
232 |
|
233 template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, true, true> { |
|
234 // LHS and RHS are signed types |
|
235 |
|
236 // Helper function |
|
237 static inline bool signsMatch(LHS lhs, RHS rhs) |
|
238 { |
|
239 return (lhs ^ rhs) >= 0; |
|
240 } |
|
241 |
|
242 static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN |
|
243 { |
|
244 if (signsMatch(lhs, rhs)) { |
|
245 if (lhs >= 0) { |
|
246 if ((::std::numeric_limits<ResultType>::max() - rhs) < lhs) |
|
247 return false; |
|
248 } else { |
|
249 ResultType temp = lhs - ::std::numeric_limits<ResultType>::min(); |
|
250 if (rhs < -temp) |
|
251 return false; |
|
252 } |
|
253 } // if the signs do not match this operation can't overflow |
|
254 result = lhs + rhs; |
|
255 return true; |
|
256 } |
|
257 |
|
258 static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN |
|
259 { |
|
260 if (!signsMatch(lhs, rhs)) { |
|
261 if (lhs >= 0) { |
|
262 if (lhs > ::std::numeric_limits<ResultType>::max() + rhs) |
|
263 return false; |
|
264 } else { |
|
265 if (rhs > ::std::numeric_limits<ResultType>::max() + lhs) |
|
266 return false; |
|
267 } |
|
268 } // if the signs match this operation can't overflow |
|
269 result = lhs - rhs; |
|
270 return true; |
|
271 } |
|
272 |
|
273 static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN |
|
274 { |
|
275 if (signsMatch(lhs, rhs)) { |
|
276 if (lhs >= 0) { |
|
277 if (lhs && (::std::numeric_limits<ResultType>::max() / lhs) < rhs) |
|
278 return false; |
|
279 } else { |
|
280 if (lhs == ::std::numeric_limits<ResultType>::min() || rhs == ::std::numeric_limits<ResultType>::min()) |
|
281 return false; |
|
282 if ((::std::numeric_limits<ResultType>::max() / -lhs) < -rhs) |
|
283 return false; |
|
284 } |
|
285 } else { |
|
286 if (lhs < 0) { |
|
287 if (rhs && lhs < (::std::numeric_limits<ResultType>::min() / rhs)) |
|
288 return false; |
|
289 } else { |
|
290 if (lhs && rhs < (::std::numeric_limits<ResultType>::min() / lhs)) |
|
291 return false; |
|
292 } |
|
293 } |
|
294 result = lhs * rhs; |
|
295 return true; |
|
296 } |
|
297 |
|
298 static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; } |
|
299 |
|
300 }; |
|
301 |
|
302 template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, false, false> { |
|
303 // LHS and RHS are unsigned types so bounds checks are nice and easy |
|
304 static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN |
|
305 { |
|
306 ResultType temp = lhs + rhs; |
|
307 if (temp < lhs) |
|
308 return false; |
|
309 result = temp; |
|
310 return true; |
|
311 } |
|
312 |
|
313 static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN |
|
314 { |
|
315 ResultType temp = lhs - rhs; |
|
316 if (temp > lhs) |
|
317 return false; |
|
318 result = temp; |
|
319 return true; |
|
320 } |
|
321 |
|
322 static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN |
|
323 { |
|
324 ResultType temp = lhs * rhs; |
|
325 if (temp < lhs) |
|
326 return false; |
|
327 result = temp; |
|
328 return true; |
|
329 } |
|
330 |
|
331 static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; } |
|
332 |
|
333 }; |
|
334 |
|
335 template <typename ResultType> struct ArithmeticOperations<int, unsigned, ResultType, true, false> { |
|
336 static inline bool add(int64_t lhs, int64_t rhs, ResultType& result) |
|
337 { |
|
338 int64_t temp = lhs + rhs; |
|
339 if (temp < ::std::numeric_limits<ResultType>::min()) |
|
340 return false; |
|
341 if (temp > ::std::numeric_limits<ResultType>::max()) |
|
342 return false; |
|
343 result = static_cast<ResultType>(temp); |
|
344 return true; |
|
345 } |
|
346 |
|
347 static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result) |
|
348 { |
|
349 int64_t temp = lhs - rhs; |
|
350 if (temp < ::std::numeric_limits<ResultType>::min()) |
|
351 return false; |
|
352 if (temp > ::std::numeric_limits<ResultType>::max()) |
|
353 return false; |
|
354 result = static_cast<ResultType>(temp); |
|
355 return true; |
|
356 } |
|
357 |
|
358 static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result) |
|
359 { |
|
360 int64_t temp = lhs * rhs; |
|
361 if (temp < ::std::numeric_limits<ResultType>::min()) |
|
362 return false; |
|
363 if (temp > ::std::numeric_limits<ResultType>::max()) |
|
364 return false; |
|
365 result = static_cast<ResultType>(temp); |
|
366 return true; |
|
367 } |
|
368 |
|
369 static inline bool equals(int lhs, unsigned rhs) |
|
370 { |
|
371 return static_cast<int64_t>(lhs) == static_cast<int64_t>(rhs); |
|
372 } |
|
373 }; |
|
374 |
|
375 template <typename ResultType> struct ArithmeticOperations<unsigned, int, ResultType, false, true> { |
|
376 static inline bool add(int64_t lhs, int64_t rhs, ResultType& result) |
|
377 { |
|
378 return ArithmeticOperations<int, unsigned, ResultType>::add(rhs, lhs, result); |
|
379 } |
|
380 |
|
381 static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result) |
|
382 { |
|
383 return ArithmeticOperations<int, unsigned, ResultType>::sub(lhs, rhs, result); |
|
384 } |
|
385 |
|
386 static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result) |
|
387 { |
|
388 return ArithmeticOperations<int, unsigned, ResultType>::multiply(rhs, lhs, result); |
|
389 } |
|
390 |
|
391 static inline bool equals(unsigned lhs, int rhs) |
|
392 { |
|
393 return ArithmeticOperations<int, unsigned, ResultType>::equals(rhs, lhs); |
|
394 } |
|
395 }; |
|
396 |
|
397 template <typename U, typename V, typename R> static inline bool safeAdd(U lhs, V rhs, R& result) |
|
398 { |
|
399 return ArithmeticOperations<U, V, R>::add(lhs, rhs, result); |
|
400 } |
|
401 |
|
402 template <typename U, typename V, typename R> static inline bool safeSub(U lhs, V rhs, R& result) |
|
403 { |
|
404 return ArithmeticOperations<U, V, R>::sub(lhs, rhs, result); |
|
405 } |
|
406 |
|
407 template <typename U, typename V, typename R> static inline bool safeMultiply(U lhs, V rhs, R& result) |
|
408 { |
|
409 return ArithmeticOperations<U, V, R>::multiply(lhs, rhs, result); |
|
410 } |
|
411 |
|
412 template <typename U, typename V> static inline bool safeEquals(U lhs, V rhs) |
|
413 { |
|
414 return ArithmeticOperations<U, V>::equals(lhs, rhs); |
|
415 } |
|
416 |
|
417 enum ResultOverflowedTag { ResultOverflowed }; |
|
418 |
|
419 // FIXME: Needed to workaround http://llvm.org/bugs/show_bug.cgi?id=10801 |
|
420 static inline bool workAroundClangBug() { return true; } |
|
421 |
|
422 template <typename T, class OverflowHandler> class Checked : public OverflowHandler { |
|
423 public: |
|
424 template <typename _T, class _OverflowHandler> friend class Checked; |
|
425 Checked() |
|
426 : m_value(0) |
|
427 { |
|
428 } |
|
429 |
|
430 Checked(ResultOverflowedTag) |
|
431 : m_value(0) |
|
432 { |
|
433 // FIXME: Remove this when clang fixes http://llvm.org/bugs/show_bug.cgi?id=10801 |
|
434 if (workAroundClangBug()) |
|
435 this->overflowed(); |
|
436 } |
|
437 |
|
438 template <typename U> Checked(U value) |
|
439 { |
|
440 if (!isInBounds<T>(value)) |
|
441 this->overflowed(); |
|
442 m_value = static_cast<T>(value); |
|
443 } |
|
444 |
|
445 template <typename V> Checked(const Checked<T, V>& rhs) |
|
446 : m_value(rhs.m_value) |
|
447 { |
|
448 if (rhs.hasOverflowed()) |
|
449 this->overflowed(); |
|
450 } |
|
451 |
|
452 template <typename U> Checked(const Checked<U, OverflowHandler>& rhs) |
|
453 : OverflowHandler(rhs) |
|
454 { |
|
455 if (!isInBounds<T>(rhs.m_value)) |
|
456 this->overflowed(); |
|
457 m_value = static_cast<T>(rhs.m_value); |
|
458 } |
|
459 |
|
460 template <typename U, typename V> Checked(const Checked<U, V>& rhs) |
|
461 { |
|
462 if (rhs.hasOverflowed()) |
|
463 this->overflowed(); |
|
464 if (!isInBounds<T>(rhs.m_value)) |
|
465 this->overflowed(); |
|
466 m_value = static_cast<T>(rhs.m_value); |
|
467 } |
|
468 |
|
469 const Checked& operator=(Checked rhs) |
|
470 { |
|
471 this->clearOverflow(); |
|
472 if (rhs.hasOverflowed()) |
|
473 this->overflowed(); |
|
474 m_value = static_cast<T>(rhs.m_value); |
|
475 return *this; |
|
476 } |
|
477 |
|
478 template <typename U> const Checked& operator=(U value) |
|
479 { |
|
480 return *this = Checked(value); |
|
481 } |
|
482 |
|
483 template <typename U, typename V> const Checked& operator=(const Checked<U, V>& rhs) |
|
484 { |
|
485 return *this = Checked(rhs); |
|
486 } |
|
487 |
|
488 // prefix |
|
489 const Checked& operator++() |
|
490 { |
|
491 if (m_value == ::std::numeric_limits<T>::max()) |
|
492 this->overflowed(); |
|
493 m_value++; |
|
494 return *this; |
|
495 } |
|
496 |
|
497 const Checked& operator--() |
|
498 { |
|
499 if (m_value == ::std::numeric_limits<T>::min()) |
|
500 this->overflowed(); |
|
501 m_value--; |
|
502 return *this; |
|
503 } |
|
504 |
|
505 // postfix operators |
|
506 const Checked operator++(int) |
|
507 { |
|
508 if (m_value == ::std::numeric_limits<T>::max()) |
|
509 this->overflowed(); |
|
510 return Checked(m_value++); |
|
511 } |
|
512 |
|
513 const Checked operator--(int) |
|
514 { |
|
515 if (m_value == ::std::numeric_limits<T>::min()) |
|
516 this->overflowed(); |
|
517 return Checked(m_value--); |
|
518 } |
|
519 |
|
520 // Boolean operators |
|
521 bool operator!() const |
|
522 { |
|
523 if (this->hasOverflowed()) |
|
524 CRASH(); |
|
525 return !m_value; |
|
526 } |
|
527 |
|
528 typedef void* (Checked::*UnspecifiedBoolType); |
|
529 operator UnspecifiedBoolType*() const |
|
530 { |
|
531 if (this->hasOverflowed()) |
|
532 CRASH(); |
|
533 return (m_value) ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; |
|
534 } |
|
535 |
|
536 // Value accessors. unsafeGet() will crash if there's been an overflow. |
|
537 T unsafeGet() const |
|
538 { |
|
539 if (this->hasOverflowed()) |
|
540 CRASH(); |
|
541 return m_value; |
|
542 } |
|
543 |
|
544 bool safeGet(T& value) const WARN_UNUSED_RETURN |
|
545 { |
|
546 value = m_value; |
|
547 return this->hasOverflowed(); |
|
548 } |
|
549 |
|
550 // Mutating assignment |
|
551 template <typename U> const Checked operator+=(U rhs) |
|
552 { |
|
553 if (!safeAdd(m_value, rhs, m_value)) |
|
554 this->overflowed(); |
|
555 return *this; |
|
556 } |
|
557 |
|
558 template <typename U> const Checked operator-=(U rhs) |
|
559 { |
|
560 if (!safeSub(m_value, rhs, m_value)) |
|
561 this->overflowed(); |
|
562 return *this; |
|
563 } |
|
564 |
|
565 template <typename U> const Checked operator*=(U rhs) |
|
566 { |
|
567 if (!safeMultiply(m_value, rhs, m_value)) |
|
568 this->overflowed(); |
|
569 return *this; |
|
570 } |
|
571 |
|
572 const Checked operator*=(double rhs) |
|
573 { |
|
574 double result = rhs * m_value; |
|
575 // Handle +/- infinity and NaN |
|
576 if (!(::std::numeric_limits<T>::min() <= result && ::std::numeric_limits<T>::max() >= result)) |
|
577 this->overflowed(); |
|
578 m_value = (T)result; |
|
579 return *this; |
|
580 } |
|
581 |
|
582 const Checked operator*=(float rhs) |
|
583 { |
|
584 return *this *= (double)rhs; |
|
585 } |
|
586 |
|
587 template <typename U, typename V> const Checked operator+=(Checked<U, V> rhs) |
|
588 { |
|
589 if (rhs.hasOverflowed()) |
|
590 this->overflowed(); |
|
591 return *this += rhs.m_value; |
|
592 } |
|
593 |
|
594 template <typename U, typename V> const Checked operator-=(Checked<U, V> rhs) |
|
595 { |
|
596 if (rhs.hasOverflowed()) |
|
597 this->overflowed(); |
|
598 return *this -= rhs.m_value; |
|
599 } |
|
600 |
|
601 template <typename U, typename V> const Checked operator*=(Checked<U, V> rhs) |
|
602 { |
|
603 if (rhs.hasOverflowed()) |
|
604 this->overflowed(); |
|
605 return *this *= rhs.m_value; |
|
606 } |
|
607 |
|
608 // Equality comparisons |
|
609 template <typename V> bool operator==(Checked<T, V> rhs) |
|
610 { |
|
611 return unsafeGet() == rhs.unsafeGet(); |
|
612 } |
|
613 |
|
614 template <typename U> bool operator==(U rhs) |
|
615 { |
|
616 if (this->hasOverflowed()) |
|
617 this->overflowed(); |
|
618 return safeEquals(m_value, rhs); |
|
619 } |
|
620 |
|
621 template <typename U, typename V> const Checked operator==(Checked<U, V> rhs) |
|
622 { |
|
623 return unsafeGet() == Checked(rhs.unsafeGet()); |
|
624 } |
|
625 |
|
626 template <typename U> bool operator!=(U rhs) |
|
627 { |
|
628 return !(*this == rhs); |
|
629 } |
|
630 |
|
631 private: |
|
632 // Disallow implicit conversion of floating point to integer types |
|
633 Checked(float); |
|
634 Checked(double); |
|
635 void operator=(float); |
|
636 void operator=(double); |
|
637 void operator+=(float); |
|
638 void operator+=(double); |
|
639 void operator-=(float); |
|
640 void operator-=(double); |
|
641 T m_value; |
|
642 }; |
|
643 |
|
644 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs) |
|
645 { |
|
646 U x = 0; |
|
647 V y = 0; |
|
648 bool overflowed = lhs.safeGet(x) || rhs.safeGet(y); |
|
649 typename Result<U, V>::ResultType result = 0; |
|
650 overflowed |= !safeAdd(x, y, result); |
|
651 if (overflowed) |
|
652 return ResultOverflowed; |
|
653 return result; |
|
654 } |
|
655 |
|
656 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs) |
|
657 { |
|
658 U x = 0; |
|
659 V y = 0; |
|
660 bool overflowed = lhs.safeGet(x) || rhs.safeGet(y); |
|
661 typename Result<U, V>::ResultType result = 0; |
|
662 overflowed |= !safeSub(x, y, result); |
|
663 if (overflowed) |
|
664 return ResultOverflowed; |
|
665 return result; |
|
666 } |
|
667 |
|
668 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs) |
|
669 { |
|
670 U x = 0; |
|
671 V y = 0; |
|
672 bool overflowed = lhs.safeGet(x) || rhs.safeGet(y); |
|
673 typename Result<U, V>::ResultType result = 0; |
|
674 overflowed |= !safeMultiply(x, y, result); |
|
675 if (overflowed) |
|
676 return ResultOverflowed; |
|
677 return result; |
|
678 } |
|
679 |
|
680 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, V rhs) |
|
681 { |
|
682 return lhs + Checked<V, OverflowHandler>(rhs); |
|
683 } |
|
684 |
|
685 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, V rhs) |
|
686 { |
|
687 return lhs - Checked<V, OverflowHandler>(rhs); |
|
688 } |
|
689 |
|
690 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, V rhs) |
|
691 { |
|
692 return lhs * Checked<V, OverflowHandler>(rhs); |
|
693 } |
|
694 |
|
695 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(U lhs, Checked<V, OverflowHandler> rhs) |
|
696 { |
|
697 return Checked<U, OverflowHandler>(lhs) + rhs; |
|
698 } |
|
699 |
|
700 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(U lhs, Checked<V, OverflowHandler> rhs) |
|
701 { |
|
702 return Checked<U, OverflowHandler>(lhs) - rhs; |
|
703 } |
|
704 |
|
705 template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(U lhs, Checked<V, OverflowHandler> rhs) |
|
706 { |
|
707 return Checked<U, OverflowHandler>(lhs) * rhs; |
|
708 } |
|
709 |
|
710 } |
|
711 |
|
712 using WTF::Checked; |
|
713 using WTF::RecordOverflow; |
|
714 |
|
715 #endif /* yarr_CheckedArithmetic_h */ |