| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2011 Apple Inc. All rights reserved. | 2 * Copyright (C) 2011 Apple Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 * Checked<T> works for all integer types, with the following caveats: | 59 * Checked<T> works for all integer types, with the following caveats: |
| 60 * - Mixing signedness of operands is only supported for types narrower than | 60 * - Mixing signedness of operands is only supported for types narrower than |
| 61 * 64bits. | 61 * 64bits. |
| 62 * - It does have a performance impact, so tight loops may want to be careful | 62 * - It does have a performance impact, so tight loops may want to be careful |
| 63 * when using it. | 63 * when using it. |
| 64 * | 64 * |
| 65 */ | 65 */ |
| 66 | 66 |
| 67 namespace WTF { | 67 namespace WTF { |
| 68 | 68 |
| 69 enum class CheckedState { | 69 enum class CheckedState { DidOverflow, DidNotOverflow }; |
| 70 DidOverflow, | |
| 71 DidNotOverflow | |
| 72 }; | |
| 73 | 70 |
| 74 class CrashOnOverflow { | 71 class CrashOnOverflow { |
| 75 protected: | 72 protected: |
| 76 NO_RETURN_DUE_TO_CRASH void overflowed() | 73 NO_RETURN_DUE_TO_CRASH void overflowed() { CRASH(); } |
| 77 { | 74 |
| 78 CRASH(); | 75 void clearOverflow() {} |
| 79 } | 76 |
| 80 | 77 public: |
| 81 void clearOverflow() { } | 78 bool hasOverflowed() const { return false; } |
| 82 | |
| 83 public: | |
| 84 bool hasOverflowed() const { return false; } | |
| 85 }; | 79 }; |
| 86 | 80 |
| 87 class RecordOverflow { | 81 class RecordOverflow { |
| 88 protected: | 82 protected: |
| 89 RecordOverflow() | 83 RecordOverflow() : m_overflowed(false) {} |
| 90 : m_overflowed(false) | 84 |
| 91 { | 85 void overflowed() { m_overflowed = true; } |
| 92 } | 86 |
| 93 | 87 void clearOverflow() { m_overflowed = false; } |
| 94 void overflowed() | 88 |
| 95 { | 89 public: |
| 96 m_overflowed = true; | 90 bool hasOverflowed() const { return m_overflowed; } |
| 97 } | 91 |
| 98 | 92 private: |
| 99 void clearOverflow() | 93 unsigned char m_overflowed; |
| 100 { | 94 }; |
| 101 m_overflowed = false; | 95 |
| 102 } | 96 template <typename T, class OverflowHandler = CrashOnOverflow> |
| 103 | 97 class Checked; |
| 104 public: | 98 template <typename T> |
| 105 bool hasOverflowed() const { return m_overflowed; } | 99 struct RemoveChecked; |
| 106 | 100 template <typename T> |
| 107 private: | 101 struct RemoveChecked<Checked<T>>; |
| 108 unsigned char m_overflowed; | 102 |
| 109 }; | 103 template <typename Target, |
| 110 | 104 typename Source, |
| 111 template <typename T, class OverflowHandler = CrashOnOverflow> class Checked; | 105 bool targetSigned = std::numeric_limits<Target>::is_signed, |
| 112 template <typename T> struct RemoveChecked; | 106 bool sourceSigned = std::numeric_limits<Source>::is_signed> |
| 113 template <typename T> struct RemoveChecked<Checked<T>>; | 107 struct BoundsChecker; |
| 114 | 108 template <typename Target, typename Source> |
| 115 template <typename Target, typename Source, bool targetSigned = std::numeric_lim
its<Target>::is_signed, bool sourceSigned = std::numeric_limits<Source>::is_sign
ed> struct BoundsChecker; | 109 struct BoundsChecker<Target, Source, false, false> { |
| 116 template <typename Target, typename Source> struct BoundsChecker<Target, Source,
false, false> { | 110 static bool inBounds(Source value) { |
| 117 static bool inBounds(Source value) | 111 // Same signedness so implicit type conversion will always increase precisio
n |
| 118 { | 112 // to widest type |
| 119 // Same signedness so implicit type conversion will always increase prec
ision | 113 return value <= std::numeric_limits<Target>::max(); |
| 120 // to widest type | 114 } |
| 121 return value <= std::numeric_limits<Target>::max(); | 115 }; |
| 122 } | 116 |
| 123 }; | 117 template <typename Target, typename Source> |
| 124 | 118 struct BoundsChecker<Target, Source, true, true> { |
| 125 template <typename Target, typename Source> struct BoundsChecker<Target, Source,
true, true> { | 119 static bool inBounds(Source value) { |
| 126 static bool inBounds(Source value) | 120 // Same signedness so implicit type conversion will always increase precisio
n |
| 127 { | 121 // to widest type |
| 128 // Same signedness so implicit type conversion will always increase prec
ision | 122 return std::numeric_limits<Target>::min() <= value && |
| 129 // to widest type | 123 value <= std::numeric_limits<Target>::max(); |
| 130 return std::numeric_limits<Target>::min() <= value && value <= std::nume
ric_limits<Target>::max(); | 124 } |
| 131 } | 125 }; |
| 132 }; | 126 |
| 133 | 127 template <typename Target, typename Source> |
| 134 template <typename Target, typename Source> struct BoundsChecker<Target, Source,
false, true> { | 128 struct BoundsChecker<Target, Source, false, true> { |
| 135 static bool inBounds(Source value) | 129 static bool inBounds(Source value) { |
| 136 { | 130 // Target is unsigned so any value less than zero is clearly unsafe |
| 137 // Target is unsigned so any value less than zero is clearly unsafe | 131 if (value < 0) |
| 138 if (value < 0) | 132 return false; |
| 139 return false; | 133 // If our (unsigned) Target is the same or greater width we can |
| 140 // If our (unsigned) Target is the same or greater width we can | 134 // convert value to type Target without losing precision |
| 141 // convert value to type Target without losing precision | 135 if (sizeof(Target) >= sizeof(Source)) |
| 142 if (sizeof(Target) >= sizeof(Source)) | 136 return static_cast<Target>(value) <= std::numeric_limits<Target>::max(); |
| 143 return static_cast<Target>(value) <= std::numeric_limits<Target>::ma
x(); | 137 // The signed Source type has greater precision than the target so |
| 144 // The signed Source type has greater precision than the target so | 138 // max(Target) -> Source will widen. |
| 145 // max(Target) -> Source will widen. | 139 return value <= static_cast<Source>(std::numeric_limits<Target>::max()); |
| 146 return value <= static_cast<Source>(std::numeric_limits<Target>::max()); | 140 } |
| 147 } | 141 }; |
| 148 }; | 142 |
| 149 | 143 template <typename Target, typename Source> |
| 150 template <typename Target, typename Source> struct BoundsChecker<Target, Source,
true, false> { | 144 struct BoundsChecker<Target, Source, true, false> { |
| 151 static bool inBounds(Source value) | 145 static bool inBounds(Source value) { |
| 152 { | 146 // Signed target with an unsigned source |
| 153 // Signed target with an unsigned source | 147 if (sizeof(Target) <= sizeof(Source)) |
| 154 if (sizeof(Target) <= sizeof(Source)) | 148 return value <= static_cast<Source>(std::numeric_limits<Target>::max()); |
| 155 return value <= static_cast<Source>(std::numeric_limits<Target>::max
()); | 149 // Target is Wider than Source so we're guaranteed to fit any value in |
| 156 // Target is Wider than Source so we're guaranteed to fit any value in | 150 // unsigned Source |
| 157 // unsigned Source | 151 return true; |
| 158 return true; | 152 } |
| 159 } | 153 }; |
| 160 }; | 154 |
| 161 | 155 template <typename Target, |
| 162 template <typename Target, typename Source, bool CanElide = std::is_same<Target,
Source>::value || (sizeof(Target) > sizeof(Source)) > struct BoundsCheckElider; | 156 typename Source, |
| 163 template <typename Target, typename Source> struct BoundsCheckElider<Target, Sou
rce, true> { | 157 bool CanElide = std::is_same<Target, Source>::value || |
| 164 static bool inBounds(Source) { return true; } | 158 (sizeof(Target) > sizeof(Source))> |
| 165 }; | 159 struct BoundsCheckElider; |
| 166 template <typename Target, typename Source> struct BoundsCheckElider<Target, Sou
rce, false> : public BoundsChecker<Target, Source> { | 160 template <typename Target, typename Source> |
| 167 }; | 161 struct BoundsCheckElider<Target, Source, true> { |
| 168 | 162 static bool inBounds(Source) { return true; } |
| 169 template <typename Target, typename Source> static inline bool isInBounds(Source
value) | 163 }; |
| 170 { | 164 template <typename Target, typename Source> |
| 171 return BoundsCheckElider<Target, Source>::inBounds(value); | 165 struct BoundsCheckElider<Target, Source, false> |
| 172 } | 166 : public BoundsChecker<Target, Source> {}; |
| 173 | 167 |
| 174 template <typename T> struct RemoveChecked { | 168 template <typename Target, typename Source> |
| 175 typedef T CleanType; | 169 static inline bool isInBounds(Source value) { |
| 176 static const CleanType DefaultValue = 0; | 170 return BoundsCheckElider<Target, Source>::inBounds(value); |
| 177 }; | 171 } |
| 178 | 172 |
| 179 template <typename T> struct RemoveChecked<Checked<T, CrashOnOverflow>> { | 173 template <typename T> |
| 180 typedef typename RemoveChecked<T>::CleanType CleanType; | 174 struct RemoveChecked { |
| 181 static const CleanType DefaultValue = 0; | 175 typedef T CleanType; |
| 182 }; | 176 static const CleanType DefaultValue = 0; |
| 183 | 177 }; |
| 184 template <typename T> struct RemoveChecked<Checked<T, RecordOverflow>> { | 178 |
| 185 typedef typename RemoveChecked<T>::CleanType CleanType; | 179 template <typename T> |
| 186 static const CleanType DefaultValue = 0; | 180 struct RemoveChecked<Checked<T, CrashOnOverflow>> { |
| 181 typedef typename RemoveChecked<T>::CleanType CleanType; |
| 182 static const CleanType DefaultValue = 0; |
| 183 }; |
| 184 |
| 185 template <typename T> |
| 186 struct RemoveChecked<Checked<T, RecordOverflow>> { |
| 187 typedef typename RemoveChecked<T>::CleanType CleanType; |
| 188 static const CleanType DefaultValue = 0; |
| 187 }; | 189 }; |
| 188 | 190 |
| 189 // The ResultBase and SignednessSelector are used to workaround typeof not being | 191 // The ResultBase and SignednessSelector are used to workaround typeof not being |
| 190 // available in MSVC | 192 // available in MSVC |
| 191 template <typename U, typename V, bool uIsBigger = (sizeof(U) > sizeof(V)), bool
sameSize = (sizeof(U) == sizeof(V))> struct ResultBase; | 193 template <typename U, |
| 192 template <typename U, typename V> struct ResultBase<U, V, true, false> { | 194 typename V, |
| 193 typedef U ResultType; | 195 bool uIsBigger = (sizeof(U) > sizeof(V)), |
| 194 }; | 196 bool sameSize = (sizeof(U) == sizeof(V))> |
| 195 | 197 struct ResultBase; |
| 196 template <typename U, typename V> struct ResultBase<U, V, false, false> { | 198 template <typename U, typename V> |
| 197 typedef V ResultType; | 199 struct ResultBase<U, V, true, false> { |
| 198 }; | 200 typedef U ResultType; |
| 199 | 201 }; |
| 200 template <typename U> struct ResultBase<U, U, false, true> { | 202 |
| 201 typedef U ResultType; | 203 template <typename U, typename V> |
| 202 }; | 204 struct ResultBase<U, V, false, false> { |
| 203 | 205 typedef V ResultType; |
| 204 template <typename U, typename V, bool uIsSigned = std::numeric_limits<U>::is_si
gned, bool vIsSigned = std::numeric_limits<V>::is_signed> struct SignednessSelec
tor; | 206 }; |
| 205 template <typename U, typename V> struct SignednessSelector<U, V, true, true> { | 207 |
| 206 typedef U ResultType; | 208 template <typename U> |
| 207 }; | 209 struct ResultBase<U, U, false, true> { |
| 208 | 210 typedef U ResultType; |
| 209 template <typename U, typename V> struct SignednessSelector<U, V, false, false>
{ | 211 }; |
| 210 typedef U ResultType; | 212 |
| 211 }; | 213 template <typename U, |
| 212 | 214 typename V, |
| 213 template <typename U, typename V> struct SignednessSelector<U, V, true, false> { | 215 bool uIsSigned = std::numeric_limits<U>::is_signed, |
| 214 typedef V ResultType; | 216 bool vIsSigned = std::numeric_limits<V>::is_signed> |
| 215 }; | 217 struct SignednessSelector; |
| 216 | 218 template <typename U, typename V> |
| 217 template <typename U, typename V> struct SignednessSelector<U, V, false, true> { | 219 struct SignednessSelector<U, V, true, true> { |
| 218 typedef U ResultType; | 220 typedef U ResultType; |
| 219 }; | 221 }; |
| 220 | 222 |
| 221 template <typename U, typename V> struct ResultBase<U, V, false, true> { | 223 template <typename U, typename V> |
| 222 typedef typename SignednessSelector<U, V>::ResultType ResultType; | 224 struct SignednessSelector<U, V, false, false> { |
| 223 }; | 225 typedef U ResultType; |
| 224 | 226 }; |
| 225 template <typename U, typename V> struct Result : ResultBase<typename RemoveChec
ked<U>::CleanType, typename RemoveChecked<V>::CleanType> { | 227 |
| 226 }; | 228 template <typename U, typename V> |
| 227 | 229 struct SignednessSelector<U, V, true, false> { |
| 228 template <typename LHS, typename RHS, typename ResultType = typename Result<LHS,
RHS>::ResultType, | 230 typedef V ResultType; |
| 229 bool lhsSigned = std::numeric_limits<LHS>::is_signed, bool rhsSigned = std::
numeric_limits<RHS>::is_signed> struct ArithmeticOperations; | 231 }; |
| 230 | 232 |
| 231 template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOper
ations<LHS, RHS, ResultType, true, true> { | 233 template <typename U, typename V> |
| 232 // LHS and RHS are signed types | 234 struct SignednessSelector<U, V, false, true> { |
| 233 | 235 typedef U ResultType; |
| 234 // Helper function | 236 }; |
| 235 static inline bool signsMatch(LHS lhs, RHS rhs) | 237 |
| 236 { | 238 template <typename U, typename V> |
| 237 return (lhs ^ rhs) >= 0; | 239 struct ResultBase<U, V, false, true> { |
| 240 typedef typename SignednessSelector<U, V>::ResultType ResultType; |
| 241 }; |
| 242 |
| 243 template <typename U, typename V> |
| 244 struct Result : ResultBase<typename RemoveChecked<U>::CleanType, |
| 245 typename RemoveChecked<V>::CleanType> {}; |
| 246 |
| 247 template <typename LHS, |
| 248 typename RHS, |
| 249 typename ResultType = typename Result<LHS, RHS>::ResultType, |
| 250 bool lhsSigned = std::numeric_limits<LHS>::is_signed, |
| 251 bool rhsSigned = std::numeric_limits<RHS>::is_signed> |
| 252 struct ArithmeticOperations; |
| 253 |
| 254 template <typename LHS, typename RHS, typename ResultType> |
| 255 struct ArithmeticOperations<LHS, RHS, ResultType, true, true> { |
| 256 // LHS and RHS are signed types |
| 257 |
| 258 // Helper function |
| 259 static inline bool signsMatch(LHS lhs, RHS rhs) { return (lhs ^ rhs) >= 0; } |
| 260 |
| 261 static inline bool add(LHS lhs, |
| 262 RHS rhs, |
| 263 ResultType& result) WARN_UNUSED_RETURN { |
| 264 if (signsMatch(lhs, rhs)) { |
| 265 if (lhs >= 0) { |
| 266 if ((std::numeric_limits<ResultType>::max() - rhs) < lhs) |
| 267 return false; |
| 268 } else { |
| 269 ResultType temp = lhs - std::numeric_limits<ResultType>::min(); |
| 270 if (rhs < -temp) |
| 271 return false; |
| 272 } |
| 273 } // if the signs do not match this operation can't overflow |
| 274 result = static_cast<ResultType>(lhs + rhs); |
| 275 return true; |
| 276 } |
| 277 |
| 278 static inline bool sub(LHS lhs, |
| 279 RHS rhs, |
| 280 ResultType& result) WARN_UNUSED_RETURN { |
| 281 if (!signsMatch(lhs, rhs)) { |
| 282 if (lhs >= 0) { |
| 283 if (lhs > std::numeric_limits<ResultType>::max() + rhs) |
| 284 return false; |
| 285 } else { |
| 286 if (rhs > std::numeric_limits<ResultType>::max() + lhs) |
| 287 return false; |
| 288 } |
| 289 } // if the signs match this operation can't overflow |
| 290 result = static_cast<ResultType>(lhs - rhs); |
| 291 return true; |
| 292 } |
| 293 |
| 294 static inline bool multiply(LHS lhs, |
| 295 RHS rhs, |
| 296 ResultType& result) WARN_UNUSED_RETURN { |
| 297 if (signsMatch(lhs, rhs)) { |
| 298 if (lhs >= 0) { |
| 299 if (lhs && (std::numeric_limits<ResultType>::max() / lhs) < rhs) |
| 300 return false; |
| 301 } else { |
| 302 if (static_cast<ResultType>(lhs) == |
| 303 std::numeric_limits<ResultType>::min() || |
| 304 static_cast<ResultType>(rhs) == |
| 305 std::numeric_limits<ResultType>::min()) |
| 306 return false; |
| 307 if ((std::numeric_limits<ResultType>::max() / -lhs) < -rhs) |
| 308 return false; |
| 309 } |
| 310 } else { |
| 311 if (lhs < 0) { |
| 312 if (rhs && lhs < (std::numeric_limits<ResultType>::min() / rhs)) |
| 313 return false; |
| 314 } else { |
| 315 if (lhs && rhs < (std::numeric_limits<ResultType>::min() / lhs)) |
| 316 return false; |
| 317 } |
| 238 } | 318 } |
| 239 | 319 result = static_cast<ResultType>(lhs * rhs); |
| 240 static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RET
URN | 320 return true; |
| 241 { | 321 } |
| 242 if (signsMatch(lhs, rhs)) { | 322 |
| 243 if (lhs >= 0) { | 323 static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; } |
| 244 if ((std::numeric_limits<ResultType>::max() - rhs) < lhs) | 324 }; |
| 245 return false; | 325 |
| 246 } else { | 326 template <typename LHS, typename RHS, typename ResultType> |
| 247 ResultType temp = lhs - std::numeric_limits<ResultType>::min(); | 327 struct ArithmeticOperations<LHS, RHS, ResultType, false, false> { |
| 248 if (rhs < -temp) | 328 // LHS and RHS are unsigned types so bounds checks are nice and easy |
| 249 return false; | 329 static inline bool add(LHS lhs, |
| 250 } | 330 RHS rhs, |
| 251 } // if the signs do not match this operation can't overflow | 331 ResultType& result) WARN_UNUSED_RETURN { |
| 252 result = static_cast<ResultType>(lhs + rhs); | 332 ResultType temp = lhs + rhs; |
| 253 return true; | 333 if (temp < lhs) |
| 334 return false; |
| 335 result = temp; |
| 336 return true; |
| 337 } |
| 338 |
| 339 static inline bool sub(LHS lhs, |
| 340 RHS rhs, |
| 341 ResultType& result) WARN_UNUSED_RETURN { |
| 342 ResultType temp = lhs - rhs; |
| 343 if (temp > lhs) |
| 344 return false; |
| 345 result = temp; |
| 346 return true; |
| 347 } |
| 348 |
| 349 static inline bool multiply(LHS lhs, |
| 350 RHS rhs, |
| 351 ResultType& result) WARN_UNUSED_RETURN { |
| 352 if (!lhs || !rhs) { |
| 353 result = 0; |
| 354 return true; |
| 254 } | 355 } |
| 255 | 356 if (std::numeric_limits<ResultType>::max() / lhs < rhs) |
| 256 static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RET
URN | 357 return false; |
| 257 { | 358 result = lhs * rhs; |
| 258 if (!signsMatch(lhs, rhs)) { | 359 return true; |
| 259 if (lhs >= 0) { | 360 } |
| 260 if (lhs > std::numeric_limits<ResultType>::max() + rhs) | 361 |
| 261 return false; | 362 static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; } |
| 262 } else { | 363 }; |
| 263 if (rhs > std::numeric_limits<ResultType>::max() + lhs) | 364 |
| 264 return false; | 365 template <typename ResultType> |
| 265 } | 366 struct ArithmeticOperations<int, unsigned, ResultType, true, false> { |
| 266 } // if the signs match this operation can't overflow | 367 static inline bool add(int64_t lhs, int64_t rhs, ResultType& result) { |
| 267 result = static_cast<ResultType>(lhs - rhs); | 368 int64_t temp = lhs + rhs; |
| 268 return true; | 369 if (temp < std::numeric_limits<ResultType>::min()) |
| 269 } | 370 return false; |
| 270 | 371 if (temp > std::numeric_limits<ResultType>::max()) |
| 271 static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSE
D_RETURN | 372 return false; |
| 272 { | 373 result = static_cast<ResultType>(temp); |
| 273 if (signsMatch(lhs, rhs)) { | 374 return true; |
| 274 if (lhs >= 0) { | 375 } |
| 275 if (lhs && (std::numeric_limits<ResultType>::max() / lhs) < rhs) | 376 |
| 276 return false; | 377 static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result) { |
| 277 } else { | 378 int64_t temp = lhs - rhs; |
| 278 if (static_cast<ResultType>(lhs) == std::numeric_limits<ResultTy
pe>::min() || static_cast<ResultType>(rhs) == std::numeric_limits<ResultType>::m
in()) | 379 if (temp < std::numeric_limits<ResultType>::min()) |
| 279 return false; | 380 return false; |
| 280 if ((std::numeric_limits<ResultType>::max() / -lhs) < -rhs) | 381 if (temp > std::numeric_limits<ResultType>::max()) |
| 281 return false; | 382 return false; |
| 282 } | 383 result = static_cast<ResultType>(temp); |
| 283 } else { | 384 return true; |
| 284 if (lhs < 0) { | 385 } |
| 285 if (rhs && lhs < (std::numeric_limits<ResultType>::min() / rhs)) | 386 |
| 286 return false; | 387 static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result) { |
| 287 } else { | 388 int64_t temp = lhs * rhs; |
| 288 if (lhs && rhs < (std::numeric_limits<ResultType>::min() / lhs)) | 389 if (temp < std::numeric_limits<ResultType>::min()) |
| 289 return false; | 390 return false; |
| 290 } | 391 if (temp > std::numeric_limits<ResultType>::max()) |
| 291 } | 392 return false; |
| 292 result = static_cast<ResultType>(lhs * rhs); | 393 result = static_cast<ResultType>(temp); |
| 293 return true; | 394 return true; |
| 294 } | 395 } |
| 295 | 396 |
| 296 static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; } | 397 static inline bool equals(int lhs, unsigned rhs) { |
| 297 | 398 return static_cast<int64_t>(lhs) == static_cast<int64_t>(rhs); |
| 298 }; | 399 } |
| 299 | 400 }; |
| 300 template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOper
ations<LHS, RHS, ResultType, false, false> { | 401 |
| 301 // LHS and RHS are unsigned types so bounds checks are nice and easy | 402 template <typename ResultType> |
| 302 static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RET
URN | 403 struct ArithmeticOperations<unsigned, int, ResultType, false, true> { |
| 303 { | 404 static inline bool add(int64_t lhs, int64_t rhs, ResultType& result) { |
| 304 ResultType temp = lhs + rhs; | 405 return ArithmeticOperations<int, unsigned, ResultType>::add(rhs, lhs, |
| 305 if (temp < lhs) | 406 result); |
| 306 return false; | 407 } |
| 307 result = temp; | 408 |
| 308 return true; | 409 static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result) { |
| 309 } | 410 return ArithmeticOperations<int, unsigned, ResultType>::sub(lhs, rhs, |
| 310 | 411 result); |
| 311 static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RET
URN | 412 } |
| 312 { | 413 |
| 313 ResultType temp = lhs - rhs; | 414 static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result) { |
| 314 if (temp > lhs) | 415 return ArithmeticOperations<int, unsigned, ResultType>::multiply(rhs, lhs, |
| 315 return false; | 416 result); |
| 316 result = temp; | 417 } |
| 317 return true; | 418 |
| 318 } | 419 static inline bool equals(unsigned lhs, int rhs) { |
| 319 | 420 return ArithmeticOperations<int, unsigned, ResultType>::equals(rhs, lhs); |
| 320 static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSE
D_RETURN | 421 } |
| 321 { | 422 }; |
| 322 if (!lhs || !rhs) { | 423 |
| 323 result = 0; | 424 template <typename U, typename V, typename R> |
| 324 return true; | 425 static inline bool safeAdd(U lhs, V rhs, R& result) { |
| 325 } | 426 return ArithmeticOperations<U, V, R>::add(lhs, rhs, result); |
| 326 if (std::numeric_limits<ResultType>::max() / lhs < rhs) | 427 } |
| 327 return false; | 428 |
| 328 result = lhs * rhs; | 429 template <typename U, typename V, typename R> |
| 329 return true; | 430 static inline bool safeSub(U lhs, V rhs, R& result) { |
| 330 } | 431 return ArithmeticOperations<U, V, R>::sub(lhs, rhs, result); |
| 331 | 432 } |
| 332 static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; } | 433 |
| 333 | 434 template <typename U, typename V, typename R> |
| 334 }; | 435 static inline bool safeMultiply(U lhs, V rhs, R& result) { |
| 335 | 436 return ArithmeticOperations<U, V, R>::multiply(lhs, rhs, result); |
| 336 template <typename ResultType> struct ArithmeticOperations<int, unsigned, Result
Type, true, false> { | 437 } |
| 337 static inline bool add(int64_t lhs, int64_t rhs, ResultType& result) | 438 |
| 338 { | 439 template <typename U, typename V> |
| 339 int64_t temp = lhs + rhs; | 440 static inline bool safeEquals(U lhs, V rhs) { |
| 340 if (temp < std::numeric_limits<ResultType>::min()) | 441 return ArithmeticOperations<U, V>::equals(lhs, rhs); |
| 341 return false; | |
| 342 if (temp > std::numeric_limits<ResultType>::max()) | |
| 343 return false; | |
| 344 result = static_cast<ResultType>(temp); | |
| 345 return true; | |
| 346 } | |
| 347 | |
| 348 static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result) | |
| 349 { | |
| 350 int64_t temp = lhs - rhs; | |
| 351 if (temp < std::numeric_limits<ResultType>::min()) | |
| 352 return false; | |
| 353 if (temp > std::numeric_limits<ResultType>::max()) | |
| 354 return false; | |
| 355 result = static_cast<ResultType>(temp); | |
| 356 return true; | |
| 357 } | |
| 358 | |
| 359 static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result) | |
| 360 { | |
| 361 int64_t temp = lhs * rhs; | |
| 362 if (temp < std::numeric_limits<ResultType>::min()) | |
| 363 return false; | |
| 364 if (temp > std::numeric_limits<ResultType>::max()) | |
| 365 return false; | |
| 366 result = static_cast<ResultType>(temp); | |
| 367 return true; | |
| 368 } | |
| 369 | |
| 370 static inline bool equals(int lhs, unsigned rhs) | |
| 371 { | |
| 372 return static_cast<int64_t>(lhs) == static_cast<int64_t>(rhs); | |
| 373 } | |
| 374 }; | |
| 375 | |
| 376 template <typename ResultType> struct ArithmeticOperations<unsigned, int, Result
Type, false, true> { | |
| 377 static inline bool add(int64_t lhs, int64_t rhs, ResultType& result) | |
| 378 { | |
| 379 return ArithmeticOperations<int, unsigned, ResultType>::add(rhs, lhs, re
sult); | |
| 380 } | |
| 381 | |
| 382 static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result) | |
| 383 { | |
| 384 return ArithmeticOperations<int, unsigned, ResultType>::sub(lhs, rhs, re
sult); | |
| 385 } | |
| 386 | |
| 387 static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result) | |
| 388 { | |
| 389 return ArithmeticOperations<int, unsigned, ResultType>::multiply(rhs, lh
s, result); | |
| 390 } | |
| 391 | |
| 392 static inline bool equals(unsigned lhs, int rhs) | |
| 393 { | |
| 394 return ArithmeticOperations<int, unsigned, ResultType>::equals(rhs, lhs)
; | |
| 395 } | |
| 396 }; | |
| 397 | |
| 398 template <typename U, typename V, typename R> static inline bool safeAdd(U lhs,
V rhs, R& result) | |
| 399 { | |
| 400 return ArithmeticOperations<U, V, R>::add(lhs, rhs, result); | |
| 401 } | |
| 402 | |
| 403 template <typename U, typename V, typename R> static inline bool safeSub(U lhs,
V rhs, R& result) | |
| 404 { | |
| 405 return ArithmeticOperations<U, V, R>::sub(lhs, rhs, result); | |
| 406 } | |
| 407 | |
| 408 template <typename U, typename V, typename R> static inline bool safeMultiply(U
lhs, V rhs, R& result) | |
| 409 { | |
| 410 return ArithmeticOperations<U, V, R>::multiply(lhs, rhs, result); | |
| 411 } | |
| 412 | |
| 413 template <typename U, typename V> static inline bool safeEquals(U lhs, V rhs) | |
| 414 { | |
| 415 return ArithmeticOperations<U, V>::equals(lhs, rhs); | |
| 416 } | 442 } |
| 417 | 443 |
| 418 enum ResultOverflowedTag { ResultOverflowed }; | 444 enum ResultOverflowedTag { ResultOverflowed }; |
| 419 | 445 |
| 420 template <typename T, class OverflowHandler> class Checked : public OverflowHand
ler { | 446 template <typename T, class OverflowHandler> |
| 421 public: | 447 class Checked : public OverflowHandler { |
| 422 template <typename _T, class _OverflowHandler> friend class Checked; | 448 public: |
| 423 Checked() | 449 template <typename _T, class _OverflowHandler> |
| 424 : m_value(0) | 450 friend class Checked; |
| 425 { | 451 Checked() : m_value(0) {} |
| 426 } | 452 |
| 427 | 453 Checked(ResultOverflowedTag) : m_value(0) { this->overflowed(); } |
| 428 Checked(ResultOverflowedTag) | 454 |
| 429 : m_value(0) | 455 template <typename U> |
| 430 { | 456 Checked(U value) { |
| 431 this->overflowed(); | 457 if (!isInBounds<T>(value)) |
| 432 } | 458 this->overflowed(); |
| 433 | 459 m_value = static_cast<T>(value); |
| 434 template <typename U> Checked(U value) | 460 } |
| 435 { | 461 |
| 436 if (!isInBounds<T>(value)) | 462 template <typename V> |
| 437 this->overflowed(); | 463 Checked(const Checked<T, V>& rhs) : m_value(rhs.m_value) { |
| 438 m_value = static_cast<T>(value); | 464 if (rhs.hasOverflowed()) |
| 439 } | 465 this->overflowed(); |
| 440 | 466 } |
| 441 template <typename V> Checked(const Checked<T, V>& rhs) | 467 |
| 442 : m_value(rhs.m_value) | 468 template <typename U> |
| 443 { | 469 Checked(const Checked<U, OverflowHandler>& rhs) : OverflowHandler(rhs) { |
| 444 if (rhs.hasOverflowed()) | 470 if (!isInBounds<T>(rhs.m_value)) |
| 445 this->overflowed(); | 471 this->overflowed(); |
| 446 } | 472 m_value = static_cast<T>(rhs.m_value); |
| 447 | 473 } |
| 448 template <typename U> Checked(const Checked<U, OverflowHandler>& rhs) | 474 |
| 449 : OverflowHandler(rhs) | 475 template <typename U, typename V> |
| 450 { | 476 Checked(const Checked<U, V>& rhs) { |
| 451 if (!isInBounds<T>(rhs.m_value)) | 477 if (rhs.hasOverflowed()) |
| 452 this->overflowed(); | 478 this->overflowed(); |
| 453 m_value = static_cast<T>(rhs.m_value); | 479 if (!isInBounds<T>(rhs.m_value)) |
| 454 } | 480 this->overflowed(); |
| 455 | 481 m_value = static_cast<T>(rhs.m_value); |
| 456 template <typename U, typename V> Checked(const Checked<U, V>& rhs) | 482 } |
| 457 { | 483 |
| 458 if (rhs.hasOverflowed()) | 484 const Checked& operator=(Checked rhs) { |
| 459 this->overflowed(); | 485 this->clearOverflow(); |
| 460 if (!isInBounds<T>(rhs.m_value)) | 486 if (rhs.hasOverflowed()) |
| 461 this->overflowed(); | 487 this->overflowed(); |
| 462 m_value = static_cast<T>(rhs.m_value); | 488 m_value = static_cast<T>(rhs.m_value); |
| 463 } | 489 return *this; |
| 464 | 490 } |
| 465 const Checked& operator=(Checked rhs) | 491 |
| 466 { | 492 template <typename U> |
| 467 this->clearOverflow(); | 493 const Checked& operator=(U value) { |
| 468 if (rhs.hasOverflowed()) | 494 return *this = Checked(value); |
| 469 this->overflowed(); | 495 } |
| 470 m_value = static_cast<T>(rhs.m_value); | 496 |
| 471 return *this; | 497 template <typename U, typename V> |
| 472 } | 498 const Checked& operator=(const Checked<U, V>& rhs) { |
| 473 | 499 return *this = Checked(rhs); |
| 474 template <typename U> const Checked& operator=(U value) | 500 } |
| 475 { | 501 |
| 476 return *this = Checked(value); | 502 // prefix |
| 477 } | 503 const Checked& operator++() { |
| 478 | 504 if (m_value == std::numeric_limits<T>::max()) |
| 479 template <typename U, typename V> const Checked& operator=(const Checked<U,
V>& rhs) | 505 this->overflowed(); |
| 480 { | 506 m_value++; |
| 481 return *this = Checked(rhs); | 507 return *this; |
| 482 } | 508 } |
| 483 | 509 |
| 484 // prefix | 510 const Checked& operator--() { |
| 485 const Checked& operator++() | 511 if (m_value == std::numeric_limits<T>::min()) |
| 486 { | 512 this->overflowed(); |
| 487 if (m_value == std::numeric_limits<T>::max()) | 513 m_value--; |
| 488 this->overflowed(); | 514 return *this; |
| 489 m_value++; | 515 } |
| 490 return *this; | 516 |
| 491 } | 517 // postfix operators |
| 492 | 518 const Checked operator++(int) { |
| 493 const Checked& operator--() | 519 if (m_value == std::numeric_limits<T>::max()) |
| 494 { | 520 this->overflowed(); |
| 495 if (m_value == std::numeric_limits<T>::min()) | 521 return Checked(m_value++); |
| 496 this->overflowed(); | 522 } |
| 497 m_value--; | 523 |
| 498 return *this; | 524 const Checked operator--(int) { |
| 499 } | 525 if (m_value == std::numeric_limits<T>::min()) |
| 500 | 526 this->overflowed(); |
| 501 // postfix operators | 527 return Checked(m_value--); |
| 502 const Checked operator++(int) | 528 } |
| 503 { | 529 |
| 504 if (m_value == std::numeric_limits<T>::max()) | 530 // Boolean operators |
| 505 this->overflowed(); | 531 bool operator!() const { |
| 506 return Checked(m_value++); | 532 if (this->hasOverflowed()) |
| 507 } | 533 CRASH(); |
| 508 | 534 return !m_value; |
| 509 const Checked operator--(int) | 535 } |
| 510 { | 536 |
| 511 if (m_value == std::numeric_limits<T>::min()) | 537 typedef void*(Checked::*UnspecifiedBoolType); |
| 512 this->overflowed(); | 538 operator UnspecifiedBoolType*() const { |
| 513 return Checked(m_value--); | 539 if (this->hasOverflowed()) |
| 514 } | 540 CRASH(); |
| 515 | 541 return (m_value) ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; |
| 516 // Boolean operators | 542 } |
| 517 bool operator!() const | 543 |
| 518 { | 544 // Value accessors. unsafeGet() will crash if there's been an overflow. |
| 519 if (this->hasOverflowed()) | 545 T unsafeGet() const { |
| 520 CRASH(); | 546 if (this->hasOverflowed()) |
| 521 return !m_value; | 547 CRASH(); |
| 522 } | 548 return m_value; |
| 523 | 549 } |
| 524 typedef void* (Checked::*UnspecifiedBoolType); | 550 |
| 525 operator UnspecifiedBoolType*() const | 551 inline CheckedState safeGet(T& value) const WARN_UNUSED_RETURN { |
| 526 { | 552 value = m_value; |
| 527 if (this->hasOverflowed()) | 553 if (this->hasOverflowed()) |
| 528 CRASH(); | 554 return CheckedState::DidOverflow; |
| 529 return (m_value) ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; | 555 return CheckedState::DidNotOverflow; |
| 530 } | 556 } |
| 531 | 557 |
| 532 // Value accessors. unsafeGet() will crash if there's been an overflow. | 558 // Mutating assignment |
| 533 T unsafeGet() const | 559 template <typename U> |
| 534 { | 560 const Checked operator+=(U rhs) { |
| 535 if (this->hasOverflowed()) | 561 if (!safeAdd(m_value, rhs, m_value)) |
| 536 CRASH(); | 562 this->overflowed(); |
| 537 return m_value; | 563 return *this; |
| 538 } | 564 } |
| 539 | 565 |
| 540 inline CheckedState safeGet(T& value) const WARN_UNUSED_RETURN | 566 template <typename U> |
| 541 { | 567 const Checked operator-=(U rhs) { |
| 542 value = m_value; | 568 if (!safeSub(m_value, rhs, m_value)) |
| 543 if (this->hasOverflowed()) | 569 this->overflowed(); |
| 544 return CheckedState::DidOverflow; | 570 return *this; |
| 545 return CheckedState::DidNotOverflow; | 571 } |
| 546 } | 572 |
| 547 | 573 template <typename U> |
| 548 // Mutating assignment | 574 const Checked operator*=(U rhs) { |
| 549 template <typename U> const Checked operator+=(U rhs) | 575 if (!safeMultiply(m_value, rhs, m_value)) |
| 550 { | 576 this->overflowed(); |
| 551 if (!safeAdd(m_value, rhs, m_value)) | 577 return *this; |
| 552 this->overflowed(); | 578 } |
| 553 return *this; | 579 |
| 554 } | 580 const Checked operator*=(double rhs) { |
| 555 | 581 double result = rhs * m_value; |
| 556 template <typename U> const Checked operator-=(U rhs) | 582 // Handle +/- infinity and NaN |
| 557 { | 583 if (!(std::numeric_limits<T>::min() <= result && |
| 558 if (!safeSub(m_value, rhs, m_value)) | 584 std::numeric_limits<T>::max() >= result)) |
| 559 this->overflowed(); | 585 this->overflowed(); |
| 560 return *this; | 586 m_value = (T)result; |
| 561 } | 587 return *this; |
| 562 | 588 } |
| 563 template <typename U> const Checked operator*=(U rhs) | 589 |
| 564 { | 590 const Checked operator*=(float rhs) { return *this *= (double)rhs; } |
| 565 if (!safeMultiply(m_value, rhs, m_value)) | 591 |
| 566 this->overflowed(); | 592 template <typename U, typename V> |
| 567 return *this; | 593 const Checked operator+=(Checked<U, V> rhs) { |
| 568 } | 594 if (rhs.hasOverflowed()) |
| 569 | 595 this->overflowed(); |
| 570 const Checked operator*=(double rhs) | 596 return *this += rhs.m_value; |
| 571 { | 597 } |
| 572 double result = rhs * m_value; | 598 |
| 573 // Handle +/- infinity and NaN | 599 template <typename U, typename V> |
| 574 if (!(std::numeric_limits<T>::min() <= result && std::numeric_limits<T>:
:max() >= result)) | 600 const Checked operator-=(Checked<U, V> rhs) { |
| 575 this->overflowed(); | 601 if (rhs.hasOverflowed()) |
| 576 m_value = (T)result; | 602 this->overflowed(); |
| 577 return *this; | 603 return *this -= rhs.m_value; |
| 578 } | 604 } |
| 579 | 605 |
| 580 const Checked operator*=(float rhs) | 606 template <typename U, typename V> |
| 581 { | 607 const Checked operator*=(Checked<U, V> rhs) { |
| 582 return *this *= (double)rhs; | 608 if (rhs.hasOverflowed()) |
| 583 } | 609 this->overflowed(); |
| 584 | 610 return *this *= rhs.m_value; |
| 585 template <typename U, typename V> const Checked operator+=(Checked<U, V> rhs
) | 611 } |
| 586 { | 612 |
| 587 if (rhs.hasOverflowed()) | 613 // Equality comparisons |
| 588 this->overflowed(); | 614 template <typename V> |
| 589 return *this += rhs.m_value; | 615 bool operator==(Checked<T, V> rhs) { |
| 590 } | 616 return unsafeGet() == rhs.unsafeGet(); |
| 591 | 617 } |
| 592 template <typename U, typename V> const Checked operator-=(Checked<U, V> rhs
) | 618 |
| 593 { | 619 template <typename U> |
| 594 if (rhs.hasOverflowed()) | 620 bool operator==(U rhs) { |
| 595 this->overflowed(); | 621 if (this->hasOverflowed()) |
| 596 return *this -= rhs.m_value; | 622 this->overflowed(); |
| 597 } | 623 return safeEquals(m_value, rhs); |
| 598 | 624 } |
| 599 template <typename U, typename V> const Checked operator*=(Checked<U, V> rhs
) | 625 |
| 600 { | 626 template <typename U, typename V> |
| 601 if (rhs.hasOverflowed()) | 627 const Checked operator==(Checked<U, V> rhs) { |
| 602 this->overflowed(); | 628 return unsafeGet() == Checked(rhs.unsafeGet()); |
| 603 return *this *= rhs.m_value; | 629 } |
| 604 } | 630 |
| 605 | 631 template <typename U> |
| 606 // Equality comparisons | 632 bool operator!=(U rhs) { |
| 607 template <typename V> bool operator==(Checked<T, V> rhs) | 633 return !(*this == rhs); |
| 608 { | 634 } |
| 609 return unsafeGet() == rhs.unsafeGet(); | 635 |
| 610 } | 636 private: |
| 611 | 637 // Disallow implicit conversion of floating point to integer types |
| 612 template <typename U> bool operator==(U rhs) | 638 Checked(float); |
| 613 { | 639 Checked(double); |
| 614 if (this->hasOverflowed()) | 640 void operator=(float); |
| 615 this->overflowed(); | 641 void operator=(double); |
| 616 return safeEquals(m_value, rhs); | 642 void operator+=(float); |
| 617 } | 643 void operator+=(double); |
| 618 | 644 void operator-=(float); |
| 619 template <typename U, typename V> const Checked operator==(Checked<U, V> rhs
) | 645 void operator-=(double); |
| 620 { | 646 T m_value; |
| 621 return unsafeGet() == Checked(rhs.unsafeGet()); | 647 }; |
| 622 } | 648 |
| 623 | 649 template <typename U, typename V, typename OverflowHandler> |
| 624 template <typename U> bool operator!=(U rhs) | 650 static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> |
| 625 { | 651 operator+(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs) { |
| 626 return !(*this == rhs); | 652 U x = 0; |
| 627 } | 653 V y = 0; |
| 628 | 654 bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || |
| 629 private: | 655 rhs.safeGet(y) == CheckedState::DidOverflow; |
| 630 // Disallow implicit conversion of floating point to integer types | 656 typename Result<U, V>::ResultType result = 0; |
| 631 Checked(float); | 657 overflowed |= !safeAdd(x, y, result); |
| 632 Checked(double); | 658 if (overflowed) |
| 633 void operator=(float); | 659 return ResultOverflowed; |
| 634 void operator=(double); | 660 return result; |
| 635 void operator+=(float); | 661 } |
| 636 void operator+=(double); | 662 |
| 637 void operator-=(float); | 663 template <typename U, typename V, typename OverflowHandler> |
| 638 void operator-=(double); | 664 static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> |
| 639 T m_value; | 665 operator-(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs) { |
| 640 }; | 666 U x = 0; |
| 641 | 667 V y = 0; |
| 642 template <typename U, typename V, typename OverflowHandler> static inline Checke
d<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, Overf
lowHandler> lhs, Checked<V, OverflowHandler> rhs) | 668 bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || |
| 643 { | 669 rhs.safeGet(y) == CheckedState::DidOverflow; |
| 644 U x = 0; | 670 typename Result<U, V>::ResultType result = 0; |
| 645 V y = 0; | 671 overflowed |= !safeSub(x, y, result); |
| 646 bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet
(y) == CheckedState::DidOverflow; | 672 if (overflowed) |
| 647 typename Result<U, V>::ResultType result = 0; | 673 return ResultOverflowed; |
| 648 overflowed |= !safeAdd(x, y, result); | 674 return result; |
| 649 if (overflowed) | 675 } |
| 650 return ResultOverflowed; | 676 |
| 651 return result; | 677 template <typename U, typename V, typename OverflowHandler> |
| 652 } | 678 static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> |
| 653 | 679 operator*(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs) { |
| 654 template <typename U, typename V, typename OverflowHandler> static inline Checke
d<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, Overf
lowHandler> lhs, Checked<V, OverflowHandler> rhs) | 680 U x = 0; |
| 655 { | 681 V y = 0; |
| 656 U x = 0; | 682 bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || |
| 657 V y = 0; | 683 rhs.safeGet(y) == CheckedState::DidOverflow; |
| 658 bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet
(y) == CheckedState::DidOverflow; | 684 typename Result<U, V>::ResultType result = 0; |
| 659 typename Result<U, V>::ResultType result = 0; | 685 overflowed |= !safeMultiply(x, y, result); |
| 660 overflowed |= !safeSub(x, y, result); | 686 if (overflowed) |
| 661 if (overflowed) | 687 return ResultOverflowed; |
| 662 return ResultOverflowed; | 688 return result; |
| 663 return result; | 689 } |
| 664 } | 690 |
| 665 | 691 template <typename U, typename V, typename OverflowHandler> |
| 666 template <typename U, typename V, typename OverflowHandler> static inline Checke
d<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, Overf
lowHandler> lhs, Checked<V, OverflowHandler> rhs) | 692 static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> |
| 667 { | 693 operator+(Checked<U, OverflowHandler> lhs, V rhs) { |
| 668 U x = 0; | 694 return lhs + Checked<V, OverflowHandler>(rhs); |
| 669 V y = 0; | 695 } |
| 670 bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet
(y) == CheckedState::DidOverflow; | 696 |
| 671 typename Result<U, V>::ResultType result = 0; | 697 template <typename U, typename V, typename OverflowHandler> |
| 672 overflowed |= !safeMultiply(x, y, result); | 698 static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> |
| 673 if (overflowed) | 699 operator-(Checked<U, OverflowHandler> lhs, V rhs) { |
| 674 return ResultOverflowed; | 700 return lhs - Checked<V, OverflowHandler>(rhs); |
| 675 return result; | 701 } |
| 676 } | 702 |
| 677 | 703 template <typename U, typename V, typename OverflowHandler> |
| 678 template <typename U, typename V, typename OverflowHandler> static inline Checke
d<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, Overf
lowHandler> lhs, V rhs) | 704 static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> |
| 679 { | 705 operator*(Checked<U, OverflowHandler> lhs, V rhs) { |
| 680 return lhs + Checked<V, OverflowHandler>(rhs); | 706 return lhs * Checked<V, OverflowHandler>(rhs); |
| 681 } | 707 } |
| 682 | 708 |
| 683 template <typename U, typename V, typename OverflowHandler> static inline Checke
d<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, Overf
lowHandler> lhs, V rhs) | 709 template <typename U, typename V, typename OverflowHandler> |
| 684 { | 710 static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> |
| 685 return lhs - Checked<V, OverflowHandler>(rhs); | 711 operator+(U lhs, Checked<V, OverflowHandler> rhs) { |
| 686 } | 712 return Checked<U, OverflowHandler>(lhs) + rhs; |
| 687 | 713 } |
| 688 template <typename U, typename V, typename OverflowHandler> static inline Checke
d<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, Overf
lowHandler> lhs, V rhs) | 714 |
| 689 { | 715 template <typename U, typename V, typename OverflowHandler> |
| 690 return lhs * Checked<V, OverflowHandler>(rhs); | 716 static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> |
| 691 } | 717 operator-(U lhs, Checked<V, OverflowHandler> rhs) { |
| 692 | 718 return Checked<U, OverflowHandler>(lhs) - rhs; |
| 693 template <typename U, typename V, typename OverflowHandler> static inline Checke
d<typename Result<U, V>::ResultType, OverflowHandler> operator+(U lhs, Checked<V
, OverflowHandler> rhs) | 719 } |
| 694 { | 720 |
| 695 return Checked<U, OverflowHandler>(lhs) + rhs; | 721 template <typename U, typename V, typename OverflowHandler> |
| 696 } | 722 static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> |
| 697 | 723 operator*(U lhs, Checked<V, OverflowHandler> rhs) { |
| 698 template <typename U, typename V, typename OverflowHandler> static inline Checke
d<typename Result<U, V>::ResultType, OverflowHandler> operator-(U lhs, Checked<V
, OverflowHandler> rhs) | 724 return Checked<U, OverflowHandler>(lhs) * rhs; |
| 699 { | 725 } |
| 700 return Checked<U, OverflowHandler>(lhs) - rhs; | |
| 701 } | |
| 702 | |
| 703 template <typename U, typename V, typename OverflowHandler> static inline Checke
d<typename Result<U, V>::ResultType, OverflowHandler> operator*(U lhs, Checked<V
, OverflowHandler> rhs) | |
| 704 { | |
| 705 return Checked<U, OverflowHandler>(lhs) * rhs; | |
| 706 } | |
| 707 | |
| 708 } | 726 } |
| 709 | 727 |
| 710 using WTF::Checked; | 728 using WTF::Checked; |
| 711 using WTF::CheckedState; | 729 using WTF::CheckedState; |
| 712 using WTF::RecordOverflow; | 730 using WTF::RecordOverflow; |
| 713 | 731 |
| 714 #endif | 732 #endif |
| OLD | NEW |